#ifndef __http_kenny_ojii2fwoeeif9w23__
#define __http_kenny_ojii2fwoeeif9w23__

#include <cstdio>
#include <cstdint>
#include <cstring>
#include <string>
#include <tuple>
#include <list>
#include <map>
#include <set>
#include <unordered_map>
#include <functional>
#include <memory>
#include <algorithm>
#include <thread>
#include <mutex>
#include <atomic>

#include <hude/base/base_type.hpp>
#include <hude/base/optional.hpp>
#include <hude/base/hex.hpp>
#include <hude/safe/base64.hpp>
#include <hude/safe/shax.hpp>
#include <hude/aio/network.hpp>

//----------------------------------------------------------------------------------------------
namespace http_v11
{
    /*********************************************************************
     * @brief ...
     */
    enum class method_t : int { emGET, emPOST, emPUT, emDELETE };

    /*********************************************************************
     * @brief ...
     */
    enum state_coder_t : int { emERROR = -1, emDONE = 0, emWAITTING = 1 };

    /*********************************************************************
     * @brief ...
     */
    enum class code_t : uint32_t
    {
        emOK = 200,
        emREQ_INVALID = 400,
        emRES_WEBSOCKET = 101,
        emNOT_FOUND = 404,
        emINTER_ERROR = 500
    };

    /*********************************************************************
     * @brief ...
     */
    using address_t = dnet::address_t;

    /*********************************************************************
     * @brief ...
     */
    using socket_t = dnet::socket_t;

    /*********************************************************************
     * @brief ...
     */
    using sockopts_t = dnet::sockopts_t;

    /*********************************************************************
     * @brief ...
     */
    using buffers_t = hude::buffers_t;

    /*********************************************************************
     * @brief ...
     */
    struct sse_message_t
    {
        sse_message_t() {}
        sse_message_t( const std::string& data, const std::string& event = "message" ) :
            id_( id() ), event_( event ), data_( data ) {}

        std::string id_;
        std::string event_;
        std::string data_;

        std::string id() { static std::size_t n; return hude::format_t{ "%u", ++n }.str(); }
    };

    /*********************************************************************
     * @brief ...
     */
    struct _channel_t
    {
        //----------------------------------------------------------------------------------------------
        virtual void terminate() = 0;

        //----------------------------------------------------------------------------------------------
        virtual address_t addr_local() = 0;
        //----------------------------------------------------------------------------------------------
        virtual address_t addr_peer() = 0;

        //----------------------------------------------------------------------------------------------
        virtual int _send( const hude::buffer_t& buffer ) = 0;

        //----------------------------------------------------------------------------------------------
        virtual int _recv( hude::buffer_t& buffer, size_t size = 0U ) = 0;

        //----------------------------------------------------------------------------------------------
        int _send( const buffers_t& buffers )
        {
            return _send( hude::merge( buffers ) );
        }

        //----------------------------------------------------------------------------------------------
        int _send( const std::string text )
        {
            return _send( hude::buffer_t{ text.begin(), text.end() } );
        }
    };

    /*********************************************************************
     * @brief ...
     */
    struct sender_sse_t
    {
        //----------------------------------------------------------------------------------------------
        virtual void terminate() = 0;

        //----------------------------------------------------------------------------------------------
        virtual address_t addr_local() = 0;
        //----------------------------------------------------------------------------------------------
        virtual address_t addr_peer() = 0;

        //----------------------------------------------------------------------------------------------
        inline state_coder_t send( const sse_message_t& m ) { return _send_sse( m ); }
        inline state_coder_t send( const std::string& d ) { return _send_sse( sse_message_t{ d } ); }
        inline state_coder_t send( const std::string& d, const std::string& e ) { return _send_sse( sse_message_t{ d, e } ); }

        //----------------------------------------------------------------------------------------------
        virtual state_coder_t _send_sse( const sse_message_t& ) = 0;
    };

    /*********************************************************************
     * @brief ...
     */
    struct sender_wsk_t
    {
        //----------------------------------------------------------------------------------------------
        enum : uint8_t { emTXT = 1U, emBIN = 2U };

        using message_t = std::tuple< uint8_t, const uint8_t*, std::size_t >;

        //----------------------------------------------------------------------------------------------
        virtual void terminate() = 0;

        //----------------------------------------------------------------------------------------------
        virtual address_t addr_local() = 0;
        //----------------------------------------------------------------------------------------------
        virtual address_t addr_peer() = 0;

        //----------------------------------------------------------------------------------------------
        inline state_coder_t send( uint8_t clz, const uint8_t* dat, std::size_t siz ) { return _send_wsk( clz, dat, siz ); }
        inline state_coder_t send( const hude::buffer_t& b ) { return _send_wsk( emBIN, &(b[0]), b.size() ); }
        inline state_coder_t send( const std::string& b ) { return _send_wsk( b ); }
        inline state_coder_t send( const char* str ) { return _send_wsk( emTXT, (const uint8_t*)str, strlen( str ) ); }

        //----------------------------------------------------------------------------------------------
        template< std::size_t _size = 4096U, typename ... _args >
        inline state_coder_t send( const char* fmt, _args&& ... args ) { return _send_wsk( hude::_format_t< 4096U >{ fmt, std::forward< _args >( args ) ... }.str() ); }

        //----------------------------------------------------------------------------------------------
        inline state_coder_t _send_wsk( const std::string& b ) { return _send_wsk( emTXT, (const uint8_t*)b.c_str(), b.size() ); }

        //----------------------------------------------------------------------------------------------
        virtual state_coder_t _send_wsk( uint8_t, const uint8_t*, std::size_t ) = 0;
    };

    /*********************************************************************
     * @brief ...
     */
    template< typename _value > struct target_type_t {};

    template<> struct target_type_t< std::string > { typedef std::string type_t; };
    template<> struct target_type_t< char* > { typedef std::string type_t; };
    template<> struct target_type_t< const char* > { typedef std::string type_t; };

    template<> struct target_type_t< int8_t   > { typedef int8_t   type_t; };
    template<> struct target_type_t< int16_t  > { typedef int16_t  type_t; };
    template<> struct target_type_t< int32_t  > { typedef int32_t  type_t; };
    template<> struct target_type_t< int64_t  > { typedef int64_t  type_t; };

    template<> struct target_type_t< uint8_t  > { typedef uint8_t  type_t; };
    template<> struct target_type_t< uint16_t > { typedef uint16_t type_t; };
    template<> struct target_type_t< uint32_t > { typedef uint32_t type_t; };
    template<> struct target_type_t< uint64_t > { typedef uint64_t type_t; };

    template<> struct target_type_t< float    > { typedef float    type_t; };
    template<> struct target_type_t< double   > { typedef double   type_t; };

    /*********************************************************************
     * @brief ...
     */
    struct _http_t
    {
        //----------------------------------------------------------------------------------------------
        typedef std::map< std::string, std::string > fields_t;

        //----------------------------------------------------------------------------------------------
        std::string     title_;
        method_t        method_;
        std::string     path_;
        fields_t        fields_;
        fields_t        args_;
        hude::buffer_t  payload_;
        code_t          code_;

        //----------------------------------------------------------------------------------------------------
        void reset()
        {
            title_ = "OK";
            method_ = method_t::emGET;
            path_.clear();
            fields_.clear();
            args_.clear();
            payload_.clear();
            code_ = code_t::emOK;
        }

        //----------------------------------------------------------------------------------------------------
        _http_t() : method_( method_t::emGET ), code_( code_t::emOK ) {}

        //----------------------------------------------------------------------------------------------------
        template< typename _value >
        inline bool value( const std::string& key, typename target_type_t< _value >::type_t& value ) const
        {
            hude::from_string_t< _value > from;

            {
                auto itr = this->args_.find( key );

                if( itr != this->args_.end() )
                {
                    value = from.get( itr->second );
                    return true;
                }
            }

            {
                auto itr = this->fields_.find( key );

                if( itr != this->fields_.end() )
                {
                    value = from.get( itr->second );
                    return true;
                }
            }

            return false;
        }

        //----------------------------------------------------------------------------------------------------
        template< typename _value >
        inline bool value( const char* key, typename target_type_t< _value >::type_t& value ) const
        {
            auto _key = std::string( key );
            return this->value< _value >( _key, value );
        }

        //----------------------------------------------------------------------------------------------------
        template< typename _value >
        inline _value value_or_default( const std::string& key, typename target_type_t< _value >::type_t def_value ) const
        {
            this->value< _value >( key, def_value );
            return def_value;
        }

        //----------------------------------------------------------------------------------------------------
        template< typename _value >
        inline _value value_or_default( const char* key, typename target_type_t< _value >::type_t def_value ) const
        {
            auto _key = std::string( key );
            return this->value_or_default< _value >( _key, def_value );
        }

        //----------------------------------------------------------------------------------------------------
        template< typename ... _args >
        inline fields_t::iterator head( const char* key, const char* fmt, _args && ... args )
        {
            hude::format_t value{ fmt, std::forward< _args >( args ) ... };

            auto ret = fields_.emplace( key, value );
            if( ! ret.second ) ret.first->second = value.str();

            return ret.first;
        }

        //----------------------------------------------------------------------------------------------------
        inline _http_t& operator()( code_t code )
        {
            return code_ = code, *this;
        }

        //----------------------------------------------------------------------------------------------------
        inline _http_t& operator()( const std::string& payload )
        {
            payload_.assign( payload.begin(), payload.end() );
            return *this;
        }

        //----------------------------------------------------------------------------------------------------
        inline _http_t& operator()( const hude::buffer_t& payload )
        {
            payload_.assign( payload.begin(), payload.end() );
            return *this;
        }

        //----------------------------------------------------------------------------------------------------
        inline _http_t& operator()( hude::buffer_t& payload )
        {
            std::swap( payload_, payload );
            return *this;
        }

        //----------------------------------------------------------------------------------------------------
        inline _http_t& operator()( hude::buffer_t&& payload )
        {
            std::swap( payload_, payload );
            return *this;
        }

        //----------------------------------------------------------------------------------------------------
        template< typename ... _args >
        inline _http_t& operator()( const char* fmt, _args && ... args )
        {
            hude::_format_t< 4096U > format( fmt, std::forward< _args >( args ) ... );

            payload_.assign( format.str().begin(), format.str().end() );

            return *this;
        }

        //----------------------------------------------------------------------------------------------
        // 解析请求头， 正常返回0， 大于0请求头未结束等待新数据，错误返回小于0
        state_coder_t _decode( const hude::buffer_t& buffer )
        {
            // split buffer to lines
            auto cb_tolines = []( buffers_t& lines, const hude::buffer_t& payload ) -> void
            {
                typedef const uint8_t* ptr_t;
                typedef std::function< void( size_t, ptr_t, ptr_t ) > cb_t;

                hude::spliter_t( &(payload[0]), &(payload[payload.size()]), "\r\n", (cb_t)[&lines]( size_t n, ptr_t b, ptr_t e ) -> void {
                    lines.push_back( hude::buffer_t( b, e ) );
                } );
            };

            buffers_t lines;
            cb_tolines( lines, buffer );

            hude::spliter_t spliter;

            if( lines.size() >= 3 )
            {
                auto itr = lines.begin();

                // head
                {
                    static const std::string ver{ "HTTP/1.1" };

                    auto& head = *lines.begin();

                    std::vector< std::string > slic( 3 );

                    {
                        using itr_t = hude::buffer_t::const_iterator;

                        hude::spliter_t::cb_t< itr_t > cb = [&slic]( size_t n, itr_t b, itr_t e ) -> void {
                            if( n < slic.size() ) slic[n] = std::string( b, e );
                        };

                        spliter( itr_t{ head.begin() }, itr_t{ head.end() }, (const char*)" ", cb );
                    }

                    if( head[0] == 'H' || head[0] == 'h' )
                    {
                        std::transform( slic[0].begin(), slic[0].end(), slic[0].begin(), ::toupper );

                        if(  ver != slic[0] ) return state_coder_t::emERROR;

                        auto n = hude::from_string_t< std::size_t >{}.get( slic[1] );
                        if( n == 0 ) return state_coder_t::emERROR;

                        code_ = (code_t)n;

                        title_ = slic[2];
                    } else {
                        std::transform( slic[2].begin(), slic[2].end(), slic[2].begin(), ::toupper );

                        if(  ver != slic[2] ) return state_coder_t::emERROR;

                        static const std::map< std::string, method_t > tm{
                            { "GET",     method_t::emGET     },
                            { "POST",    method_t::emPOST    },
                            { "PUT",     method_t::emPUT     },
                            { "DELETE",  method_t::emDELETE  }
                        };

                        auto c = tm.find( slic[0] );
                        if( c == tm.end() ) return state_coder_t::emERROR;

                        method_ = c->second;

                        // path and args
                        const std::string& path = slic[1];

                        auto s = path.find( '?' );

                        if( s == std::string::npos )
                        {
                            path_ = path;
                        } else {
                            path_ = path.substr( 0, s );

                            using itr_t = std::string::const_iterator;

                            hude::spliter_t::cb_t< itr_t > cb = [=]( size_t n, itr_t b, itr_t e ) {
                                auto s = std::find( b, e, '=' );

                                if( s != e )
                                {
                                    args_.emplace( std::string( b, s ), std::string( s + 1, e ) );
                                }
                            };

                            spliter( path.begin() + s + 1, path.end(), "&", cb );
                        }
                    }
                }

                // fields
                if( itr != lines.end() )
                {
                    for( ++itr; itr != lines.end() && itr->empty() == false; ++itr )
                    {
                        auto pos = std::find( itr->begin(), itr->end(), ':' );

                        if( pos == itr->end() ) break;

                        if( ( pos + 1 ) < itr->end() )
                        {
                            char v = *( pos + 1 );
                            auto sikp = pos + ( ( v == ' ' || v == '\t' )? 2 : 1 );

                            fields_.emplace( std::string( itr->begin(), pos ), std::string( sikp, itr->end() ) );
                        }
                    }

                    if( itr == lines.end() ) return state_coder_t::emWAITTING;

                    ++itr;

                }

                // payload
                {
                    auto content = fields_.find( "Content-Length" );

                    if( content != fields_.end() )
                    {
                        size_t siz = strtoul( content->second.c_str(), nullptr, 0 );
                        if( siz == 0 ) return state_coder_t::emDONE;

                        payload_.clear();
                        payload_.resize( siz );

                        auto cur = payload_.begin();

                        for( ; itr != lines.end() && !itr->empty() && itr->size() <= ( siz - (cur - payload_.begin()) ); ++itr )
                        {
                            cur = std::copy( itr->begin(), itr->end(), cur );
                        }

                        if( cur - payload_.begin() < siz ) return state_coder_t::emWAITTING;
                    }
                }

                lines.erase( lines.begin(), itr );
            }

            return state_coder_t::emDONE;
        }

        //----------------------------------------------------------------------------------------------
        state_coder_t _encode( buffers_t& lines, bool dire, bool http )
        {
            if( method_ > method_t::emDELETE )
            {
                return state_coder_t::emERROR;
            }

            {
                static const char* methods[] = { "GET", "POST", "PUT", "DELETE" };

                hude::format_t head;

                if( dire )
                    head( "HTTP/1.1 %03u OK\r\n", (int)code_ );
                else
                    head( "%s %s HTTP/1.1\r\n", methods[(int)method_], path_.c_str() );

                lines.push_back( hude::buffer_t{ head.str().begin(), head.str().end() } );
            }

            for( const auto& item : fields_ )
            {
                hude::format_t field{ "%s: %s\r\n", item.first.c_str(), item.second.c_str() };
                lines.push_back( hude::buffer_t{ field.str().begin(), field.str().end() } );
            }

            if( http )
            {
                hude::format_t len{ "Content-Length: %u\r\n", payload_.size() };
                lines.push_back( hude::buffer_t{ len.str().begin(), len.str().end() } );

                if( fields_.find( "Content-Type" ) == fields_.end() )
                {
                    hude::format_t tp( "Content-Type: text/plain\r\n" );
                    lines.push_back( hude::buffer_t{ tp.str().begin(), tp.str().end() } );
                }
            }

            static const char* cr = "\r\n";
            lines.push_back( hude::buffer_t{ cr, cr + 2U } );

            return emDONE;
        }

        //----------------------------------------------------------------------------------------------
        void req_sse()
        {
            method_ = method_t::emGET;

            head( "Connection", "keep-alive" );
            head( "Accept", "text/event-stream" );
            head( "Cache-Control", "no-cache" );
        }

        //----------------------------------------------------------------------------------------------
        void res_sse( std::size_t retry )
        {
            hude::format_t r{ "retry: %u\n", retry };

            code_ = code_t::emOK;

            head( "Content-Type", "text/event-stream;charset=UTF-8" );
            head( "Cache-Control", "no-cache" );
            head( "Connection", "keep-alive" );

            payload_.assign( r.str().begin(), r.str().end() );
        }

        //----------------------------------------------------------------------------------------------
        void req_wsk( const address_t& local, const address_t& peer )
        {
            std::string key;

            {
                auto t = (uintptr_t)time( nullptr );
                t += (uintptr_t)this;
                auto p = (const uint8_t*)(const void*)&t;
                auto tmp = hude::safe::sha1_t{}.update( p, p + sizeof(uintptr_t) ).result();
                key = hude::safe::base64_t::encode( tmp );
            }

            // R"(GET / HTTP/1.1\r\n)"
            method_ = method_t::emGET;

            head( "Host", "%s", peer.str().c_str() );
            head( "Origin", "%s", local.str().c_str() );
            head( "Connection", "Upgrade" );
            head( "Upgrade", "websocket" );
            head( "Sec-WebSocket-Version", "13" );
            head( "Sec-WebSocket-Key", "%s", key.c_str() );
        }

        //----------------------------------------------------------------------------------------------
        void res_wsk( const std::string key )
        {
            auto accept = wsk_key_accept( key );

            // "HTTP/1.1 101 Switching Protocols"
            code_ = code_t::emRES_WEBSOCKET;
            title_ = "Switching Protocols";

            head( "Connection", "Upgrade" );
            head( "Upgrade", "websocket" );
            head( "Sec-WebSocket-Accept", "%s", accept.c_str() );
        }

        //----------------------------------------------------------------------
        // Websocket握手检查
        bool check_wsk() const
        {
            {
                auto v = value_or_default< std::string >( "Upgrade", std::string{} );
                if( v != "websocket" ) return false;
            }

            {
                auto v = value_or_default< std::size_t >( "Sec-WebSocket-Version", std::size_t{0} );
                if( v != 13U ) return false;
            }

            return true;
        }

        //----------------------------------------------------------------------------------------------
        std::string wsk_key_accept( const std::string& key ) const
        {
            /*
                *  标准定义： https://tools.ietf.org/html/rfc6455#section-11.3.3

                *  返回： BASE64.encode( SHA1.encode( key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11' ) )

                *  以KEY（dGhlIHNhbXBsZSBub25jZQ==）计算得到结果ACCEPT（s3pPLMBiTxaQ9kYGzzhZRbK+xOo=）为示例：
                *      key + uuid => 'dGhlIHNhbXBsZSBub25jZQ==258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
                *      SHA1       => [ 0xb3, 0x7a, 0x4f, 0x2c, 0xc0, 0x62, 0x4f, 0x16, 0x90, 0xf6, 0x46, 0x06, 0xcf, 0x38, 0x59, 0x45, 0xb2, 0xbe, 0xc4, 0xea ]
                *      BASE64     => s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
                */

            // key = std::string( "dGhlIHNhbXBsZSBub25jZQ==" );
            auto tmp = hude::safe::sha1_t{}.update( key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" ).result();
            return hude::safe::base64_t::encode( tmp );
        }

        //----------------------------------------------------------------------------------------------
        // 解析请求头， 正常返回0， 大于0请求头未结束等待新数据，错误返回小于0
        state_coder_t decode( _channel_t& chl )
        {
            hude::buffer_t buffer;

            auto ret = chl._recv( buffer );
            if( ret == 0 || buffer.empty() ) return state_coder_t::emERROR;

            return _decode( buffer );
        }

        //----------------------------------------------------------------------------------------------
        state_coder_t encode( _channel_t& chl, bool dire, bool http )
        {
            buffers_t lines;

            auto ret = _encode( lines, dire, http );

            if( ret == state_coder_t::emDONE )
            {
                int err = 0;
                
                err = chl._send( lines );
                if( err <= 0 )
                {
                    log_err( "error: send http head, send() == %d", err );
                    return state_coder_t::emERROR;
                }

                if( ! payload_.empty() )
                {
                    enum : size_t { emFRAME = 4096U };

                    std::size_t count = 0;

                    auto b = payload_.cbegin();
                    auto e = payload_.cend();

                    while( b < e )
                    {
                        auto c = ( (e - b) < emFRAME )? b +  (e - b) : b + emFRAME;

                        err = chl._send( hude::buffer_t{ b, c } );
                        if( err == 0 )
                        {
                            if( count < 10U )
                            {
                                count += 1;
                                std::this_thread::sleep_for( std::chrono::milliseconds( 20U * count ) );
                                continue;
                            } else {
                                log_err( "error: send http payload, send() == %d", err );
                                return state_coder_t::emERROR;
                            }
                        }

                        b += err;
                        count =0;
                    }

                    // auto h = payload_.cbegin();
                    // log_dug( "\t -- send http payload: %d : %d", e - h, b - h );
                }
            }

            return state_coder_t::emDONE;
        }

        //----------------------------------------------------------------------------------------------
        virtual ~_http_t() {}
    };

    /*********************************************************************
     * @brief ...
     */
    struct req_t : public _http_t
    {
        //----------------------------------------------------------------------------------------------
        address_t       source_;

        //----------------------------------------------------------------------------------------------------
        inline req_t& operator=( const char* payload )
        {
            if( payload ) payload_.assign( payload, payload + strlen( payload ) );
            return *this;
        }

        //----------------------------------------------------------------------------------------------------
        inline req_t& operator=( const std::string& payload )
        {
            payload_.assign( payload.begin(), payload.end() );
            return *this;
        }

        //----------------------------------------------------------------------------------------------------
        inline req_t& operator=( const hude::buffer_t& payload )
        {
            payload_.assign( payload.begin(), payload.end() );
            return *this;
        }

        //----------------------------------------------------------------------------------------------------
        inline req_t& operator=( hude::buffer_t& payload )
        {
            std::swap( payload_, payload );
            return *this;
        }

        //----------------------------------------------------------------------------------------------------
        inline req_t& operator=( hude::buffer_t&& payload )
        {
            std::swap( payload_, payload );
            return *this;
        }

        //----------------------------------------------------------------------------------------------
        state_coder_t encode( _channel_t& chl, bool http )
        {
            return _http_t::encode( chl, false, http );
        }
    };

    /*********************************************************************
     * @brief ...
     */
    struct res_t : public _http_t
    {
        //----------------------------------------------------------------------------------------------------
        inline res_t& operator=( const char* payload )
        {
            if( payload ) payload_.assign( payload, payload + strlen( payload ) );
            return *this;
        }

        //----------------------------------------------------------------------------------------------------
        inline res_t& operator=( const std::string& payload )
        {
            payload_.assign( payload.begin(), payload.end() );
            return *this;
        }

        //----------------------------------------------------------------------------------------------------
        inline res_t& operator=( const hude::buffer_t& payload )
        {
            payload_.assign( payload.begin(), payload.end() );
            return *this;
        }

        //----------------------------------------------------------------------------------------------------
        inline res_t& operator=( hude::buffer_t& payload )
        {
            std::swap( payload_, payload );
            return *this;
        }

        //----------------------------------------------------------------------------------------------------
        inline res_t& operator=( hude::buffer_t&& payload )
        {
            std::swap( payload_, payload );
            return *this;
        }

        //----------------------------------------------------------------------------------------------
        state_coder_t encode( _channel_t& chl, bool http )
        {
            return _http_t::encode( chl, true, http );
        }
    };

    /*********************************************************************
     * @brief ...
     */
    struct _coder_sse_t
    {
        //----------------------------------------------------------------------------------------------
        state_coder_t encode( _channel_t& chl, const sse_message_t& msg )
        {
            hude::_format_t< 2048U > message{ "id: %s\n" "event: %s\n" "data: %s\n\n",
                msg.id_.c_str(), msg.event_.c_str(), msg.data_.c_str() };

            return ( chl._send( message.str() ) == message.str().size() )? state_coder_t::emDONE : state_coder_t::emERROR;
        }

        //----------------------------------------------------------------------------------------------
        state_coder_t decode( _channel_t& chl, std::function< void( sse_message_t& ) > on_msg )
        {
            sse_message_t msg;
            hude::buffer_t buffer;
            std::list< std::string > lines;

            auto ret = chl._recv( buffer );

            if( ret != 0 )
            {
                {
                    using itr_t = hude::buffer_t::const_iterator;
                    hude::spliter_t::cb_t< itr_t > cb = [&lines]( std::size_t index, itr_t b, itr_t e ) -> void
                    {
                        lines.push_back( std::string{ b, e } );
                    };
                    
                    hude::spliter_t( buffer.begin(), buffer.end(), "\n", cb );
                }

                if( lines.empty() ) return state_coder_t::emWAITTING;

                std::map< std::string, std::string* > tab =
                {
                    { "id", &msg.id_ },
                    { "event", &msg.event_ },
                    { "data", &msg.data_ }
                };

                for( const auto& i : lines )
                {
                    auto pos = i.find( ':' );
                    if( pos == std::string::npos ) continue;

                    auto key = i.substr( 0U, pos );

                    if( i[pos + 1] == ' ' )
                    {
                        pos += 2;
                    } else {
                        pos += 1;
                    }

                    if( pos >= i.size() ) continue;

                    auto itr = tab.find( key );

                    if( itr != tab.end() ) itr->second->assign( i.substr( pos ) );
                }

                on_msg( msg );
            }

            return state_coder_t::emWAITTING;
        }
    };

    /*********************************************************************
     * @brief ...
     */
    struct _coder_wsk_t
    {
        //----------------------------------------------------------------------------------------------
        struct frame_t
        {
            uint16_t opcode   : 4;
            uint16_t rsvi3    : 1;
            uint16_t rsvi2    : 1;
            uint16_t rsvi1    : 1;
            uint16_t fin      : 1;

            uint16_t len      : 7;
            uint16_t mask     : 1;
        };

        enum : uint8_t { emTXT = 1U, emBIN = 2U };
        enum : size_t { emSIZ_BUFFER = 1024U, emSIZ_HEAD = sizeof( frame_t ) };

        using frame_buffer_t = std::tuple< frame_t, hude::buffer_t >;

        //----------------------------------------------------------------------------------------------
        std::list< frame_buffer_t >     message_;
        int                             timeout_;

        //----------------------------------------------------------------------------------------------
        _coder_wsk_t() : timeout_( 0 ) {}

        //----------------------------------------------------------------------------------------------
        state_coder_t _encode( _channel_t& chl, uint32_t mask, uint8_t type, const uint8_t* data, size_t size )
        {
            auto b = data;
            auto e = b + size;
            auto p = b;

            enum : size_t
            {
                emSIZ_FRAME = 1024,
                emSIZ_EXT = emSIZ_FRAME - sizeof( frame_t )
            };

            struct
            {
                frame_t head;
                uint8_t ext[emSIZ_EXT];
            } fm;
            
            memset( &fm, 0, sizeof( fm ) );

            fm.head.opcode = type;

            enum { emSIZ_HEAD = sizeof(fm) };

            while( p < e )
            {
                auto sl = ( e - p < 126 )? 0U : 2U;
                auto sm = mask? 4U : 0U;
                auto so = sl + sm;
                auto sd = emSIZ_EXT - so;
                auto s = ( static_cast< std::size_t >( e - p ) < sd )? e - p : sd;
                auto sss = sizeof( frame_t ) + so  + s;

                memcpy( fm.ext + so, p, s );

                if( mask )
                {
                    hude::utils::byte_order_t::value_t< uint32_t, hude::utils::byte_order_t::emNET >::set( fm.ext + sl, mask );
                    fm.head.mask = 1U;

                    unmask( fm.ext + sl, fm.ext + so, fm.ext + so + s );
                }

                if( p + s >= e ) fm.head.fin = 1;

                if( sl )
                {
                    fm.head.len = 126;
                    hude::utils::byte_order_t::value_t< uint16_t, hude::utils::byte_order_t::emBIG >::set( fm.ext, s );
                } else {
                    fm.head.len = s;
                }

                auto h = (const uint8_t*)&fm;

                // log_dug( "websock send frame( %u ): %s", fm.head.opcode, hude::utils::to_hex( h, sss ).c_str() );

                if( chl._send( hude::buffer_t{ h, h + sss } ) <= 0 )
                {
                    return state_coder_t::emERROR;
                }

                fm.head.opcode = 0;

                p += s;
            }

            return state_coder_t::emDONE;
        }

        //----------------------------------------------------------------------------------------------
        // 反掩码一桢数据
        void unmask( const uint8_t* m, uint8_t* b,  uint8_t* e )
        {
            size_t i = 0;

            // transformed[i] = original[i] XOR masking-key[ i MOD 4 ]
            for( auto p = b; p != e; ++p, ++i )
            {
                *p = *p ^ ( m[i % 4] );
            }
        }

        //----------------------------------------------------------------------------------------------
        // 接收一桢完整数据
        state_coder_t _decode_frame( _channel_t& chl, size_t mask, frame_buffer_t& frame )
        {
            auto& head = std::get<0>( frame );
            auto& data = std::get<1>( frame );

            buffers_t buffers;
            buffers.push_back( hude::buffer_t{} );
            hude::buffer_t& first = buffers.back();

            size_t offset = 0;

            uint64_t size  = 0U;
            uint64_t count  = 0U;

            uint8_t mask_key[4];

            // 如果需要mask数据，key长度一定为4
            if( mask ) mask = 4U;

            // 接收桢头
            auto ret = chl._recv( first );
            if( ret == 0 ) return state_coder_t::emERROR;
            if( first.size() < emSIZ_HEAD ) return state_coder_t::emWAITTING;

            uint8_t* h = &(first[0]);

            // 解析桢头
            {
                // 合规的opcode: 延续桢 | TXT桢 | BIN桢 | PING桢 | PONG桢
                static const auto ops = std::set< uint32_t >{ 0x00, 0x01, 0x02, 0x09, 0x0a };
                static const auto pps = std::set< uint32_t >{ 0x09, 0x0a };

                auto f = (frame_t*)h;

                // log_dug( "websock recv frame( %u ): %s", f->opcode, hude::utils::to_hex( first ).c_str() );

                // 桢头错误检查
                if( ops.find( f->opcode ) == ops.end() )
                    return state_coder_t::emERROR;
                
                // PING和PONG桢的特殊处理
                if( pps.find( f->opcode ) == pps.end() )
                {
                    if( f->mask == (mask? 0U : 1U) )
                        return state_coder_t::emERROR;
                } else {
                    mask = 0U;
                }

                // 计算数据长度和起始位置
                switch ( f->len )
                {
                case 127U:
                    // 数据在8字节的长度字段和4字节的mask-key字段之后
                    offset = ( 2 + 8 + mask );
                    size = hude::utils::byte_order_t::value_t< uint64_t >::get( (uint8_t*)( f + 1 ) );
                    break;
                
                case 126U:
                    // 数据在2字节的长度字段和4字节的mask-key字段之后
                    offset = ( 2 + 2 + mask );
                    size = hude::utils::byte_order_t::value_t< uint16_t >::get( (uint8_t*)( f + 1 ) );
                    break;
                
                default:
                    // 数据在0字节的长度字段和4字节的mask-key字段之后
                    offset = ( 2 + 0 + mask );
                    size = f->len;
                }

                if( size > emSIZ_BUFFER )
                    return state_coder_t::emERROR;

                if( mask )
                {
                    // 保存mask-key
                    memcpy( mask_key, h + offset - mask, mask );
                }

                // 桢的剩余未接收数据长度
                ret = first.size();
                ret -= offset;
                count = ( static_cast< std::size_t >( ret ) < size)? size - ret : 0;

                head = *f;
            }

            // 接收剩余数据片段
            if( count )
            {
                buffers.push_back( hude::buffer_t{} );
                hude::buffer_t& buffer = buffers.back();

                ret = chl._recv( buffer, count );

                if( ret == 0 )
                    return state_coder_t::emERROR;

                if( ret <  0 )
                    return state_coder_t::emWAITTING;
            }

            // 删除桢头
            first.erase( first.begin(),  first.begin() + offset );

            // 合并桢的数据片段
            data = hude::merge( buffers );

            if( mask )
            {
                // 还原掩码数据
                h = &(data[0]);
                unmask( mask_key, h, h + data.size() );
            }

            return head.fin? state_coder_t::emDONE : state_coder_t::emWAITTING;
        }

        //----------------------------------------------------------------------------------------------
        // 数据接收和解析
        state_coder_t _decode_message( _channel_t& chl, uint32_t mask, std::function< void( const frame_t& head, hude::buffer_t& out ) > cb )
        {
            while( true )
            {
                size_t size = 0;

                // 接收一个消息
                while( true )
                {
                    message_.push_back( frame_buffer_t{} );
                    auto& current = message_.back();

                    // 接收一桢数据
                    auto ret = this->_decode_frame( chl, mask, current );

                    // 读完一个完整websocket消息
                    if( ret == state_coder_t::emDONE )
                    {
                        hude::buffer_t out;

                        // 合并消息的所有桢
                        if( message_.size() == 1U )
                        {
                            out.swap( std::get<1>( message_.front() ) );
                        } else {
                            out.reserve( size );

                            for( auto& item : message_ )
                            {
                                auto& buffer = std::get<1>( item );
                                std::copy( buffer.begin(), buffer.end(), std::back_inserter( out ) );
                            }
                        }

                        const frame_t& head = std::get<0>( message_.front() );

                        switch( head.opcode )
                        {
                        case 0x0a:
                            timeout_ = 0;
                            break;

                        case 0x09:
                            out.clear();
                            this->pong( out );
                            chl._send( out );
                            break;

                        default:
                            cb( head, out );
                        };

                        message_.clear();
                    } else
                    // 解析数据出错
                    if( ret == state_coder_t::emERROR )
                    {
                        message_.clear();
                        return state_coder_t::emERROR;
                    } else
                    // 没有可读数据，等待下次接收事件
                    if( std::get<1>( current ).empty() )
                    {
                        message_.pop_back();
                        break;
                    } else
                    // 读到一桢数据
                    {
                        size += std::get<1>( current ).size();
                    }
                }

                return state_coder_t::emWAITTING;

            }
        }

        //----------------------------------------------------------------------------------------------
        void ping( hude::buffer_t& out )
        {
            frame_t frame;

            memset( &frame, 0, sizeof(frame_t) );

            frame.fin = 1U;
            frame.opcode = 0x09;

            auto h = (const uint8_t*)&frame;

            out = hude::buffer_t{ h, h + sizeof( frame_t ) };

            timeout_ += 1;
        }

        //----------------------------------------------------------------------------------------------
        void pong( hude::buffer_t& out )
        {
            frame_t frame;

            memset( &frame, 0, sizeof(frame_t) );

            frame.fin = 1U;
            frame.opcode = 0x0a;

            auto h = (const uint8_t*)&frame;

            out = hude::buffer_t{ h, h + sizeof( frame_t ) };
        }

        //----------------------------------------------------------------------------------------------
        state_coder_t encode( _channel_t& chl, uint32_t mask, const sender_wsk_t::message_t& msg )
        { return _encode( chl, mask, std::get<0>( msg ), std::get<1>( msg ), std::get<2>( msg ) ); }

        //----------------------------------------------------------------------------------------------
        state_coder_t decode( _channel_t& chl, uint32_t mask, std::function< void( const frame_t& head, hude::buffer_t& out ) > cb )
        { return _decode_message( chl, mask, cb ); }

        //----------------------------------------------------------------------------------------------
        int timeout() const { return timeout_; }
    };

    /*********************************************************************
     * @brief ...
     */
    struct _coder_wsk_ser_t : public _coder_wsk_t
    {
        //----------------------------------------------------------------------------------------------
        state_coder_t encode( _channel_t& chl, const sender_wsk_t::message_t& msg )
        { return _encode( chl, 0U, std::get<0>( msg ), std::get<1>( msg ), std::get<2>( msg ) ); }

        //----------------------------------------------------------------------------------------------
        state_coder_t decode( _channel_t& chl, std::function< void( const frame_t& head, hude::buffer_t& out ) > cb )
        { return _decode_message( chl, 4U, cb ); }
    };

    /*********************************************************************
     * @brief ...
     */
    struct _coder_wsk_cli_t : public _coder_wsk_t
    {
        //----------------------------------------------------------------------------------------------
        uint32_t _mask() const { static uintptr_t c; return (uint32_t)( (uintptr_t)this + (uintptr_t)time( nullptr ) + (c++) ); }

        //----------------------------------------------------------------------------------------------
        uint32_t mask() const { uint32_t ret = 0; while( ret == 0 ) { ret = _mask(); } return ret; }

        //----------------------------------------------------------------------------------------------
        state_coder_t encode( _channel_t& chl, const sender_wsk_t::message_t& msg )
        { return _encode( chl, mask(), std::get<0>( msg ), std::get<1>( msg ), std::get<2>( msg ) ); }

        //----------------------------------------------------------------------------------------------
        state_coder_t decode( _channel_t& chl, std::function< void( const frame_t& head, hude::buffer_t& out ) > cb )
        { return _decode_message( chl, 0U, cb ); }
    };

    /*********************************************************************
     * @brief ...
     */
    using cb_close_t = std::function< void( hude::any_t& ) >;

    /*********************************************************************
     * @brief ...
     */
    using cb_session_ser_htp_t = std::function< void( const address_t&, const req_t& ) >;

    /*********************************************************************
     * @brief ...
     */
    using cb_session_cli_htp_t = std::function< void( const address_t&, req_t& ) >;

    /*********************************************************************
     * @brief ...
     */
    using cb_session_ser_sse_t = std::function< void( const address_t&, hude::any_t&, std::shared_ptr< sender_sse_t > ) >;

    /*********************************************************************
     * @brief ...
     */
    using cb_session_cli_sse_t = std::function< void( const address_t&, hude::any_t& ) >;

    /*********************************************************************
     * @brief ...
     */
    using cb_session_wsk_t = std::function< void( const address_t&, hude::any_t&, std::shared_ptr< sender_wsk_t > ) >;

    /*********************************************************************
     * @brief ...
     */
    using cb_reply_t = std::function< void( const req_t&, res_t& ) >;

    /*********************************************************************
     * @brief ...
     */
    using cb_recv_sse_t = std::function< void( hude::any_t&, std::shared_ptr< sender_sse_t >, sse_message_t& ) >;

    /*********************************************************************
     * @brief ...
     */
    using cb_recv_wsk_t = std::function< void( hude::any_t&, std::shared_ptr< sender_wsk_t >, const _coder_wsk_t::frame_t&, hude::buffer_t& ) >;

    /*********************************************************************
     * @brief ...
     */
    struct cbs_base_t
    {
        cb_close_t on_close;

        cbs_base_t() {}

        cbs_base_t( cb_close_t c ) : on_close( c ) {}

        cbs_base_t( const cbs_base_t& cbs ) :
            on_close( cbs.on_close ) {}

        virtual ~cbs_base_t() {}
    };

    /*********************************************************************
     * @brief ...
     */
    struct cbs_ser_htp_t : public cbs_base_t
    {
        cb_session_ser_htp_t on_session;
        cb_reply_t on_reply;

        cbs_ser_htp_t() {}

        cbs_ser_htp_t( cb_close_t c, cb_session_ser_htp_t s, cb_reply_t r ) :
            cbs_base_t( c ), on_session( s ), on_reply( r ) {}

        cbs_ser_htp_t( const cbs_ser_htp_t& cbs ) :
            cbs_base_t( cbs.on_close ), on_session( cbs.on_session ), on_reply( cbs.on_reply ) {}
    };

    /*********************************************************************
     * @brief ...
     */
    struct cbs_ser_sse_t : public cbs_base_t
    {
        cb_session_ser_sse_t on_session;

        cbs_ser_sse_t() {}

        cbs_ser_sse_t( cb_close_t c, cb_session_ser_sse_t s ) :
            cbs_base_t( c ), on_session( s ) {}

        cbs_ser_sse_t( const cbs_ser_sse_t& cbs ) :
            cbs_base_t( cbs.on_close ), on_session( cbs.on_session ) {}
    };

    /*********************************************************************
     * @brief ...
     */
    struct cbs_ser_wsk_t : public cbs_base_t
    {
        cb_session_wsk_t on_session;
        cb_recv_wsk_t on_recv;

        cbs_ser_wsk_t() {}

        cbs_ser_wsk_t( cb_close_t c, cb_session_wsk_t s, cb_recv_wsk_t r ) :
            cbs_base_t( c ), on_session( s ), on_recv( r ) {}

        cbs_ser_wsk_t( const cbs_ser_wsk_t& cbs ) :
            cbs_base_t( cbs.on_close ), on_session( cbs.on_session ), on_recv( cbs.on_recv ) {}
    };

    /*********************************************************************
     * @brief ...
     */
    struct cbs_cli_htp_t : public cbs_base_t
    {
        cb_session_cli_htp_t on_session;
        cb_reply_t on_reply;

        cbs_cli_htp_t() {}

        cbs_cli_htp_t( cb_close_t c, cb_session_cli_htp_t s, cb_reply_t r ) :
            cbs_base_t( c ), on_session( s ), on_reply( r ) {}

        cbs_cli_htp_t( const cbs_cli_htp_t& cbs ) :
            cbs_base_t( cbs.on_close ), on_session( cbs.on_session ), on_reply( cbs.on_reply ) {}
    };

    /*********************************************************************
     * @brief ...
     */
    struct cbs_cli_sse_t : public cbs_base_t
    {
        cb_session_cli_sse_t on_session;
        cb_recv_sse_t on_recv;

        cbs_cli_sse_t() {}

        cbs_cli_sse_t( cb_close_t c, cb_session_cli_sse_t s, cb_recv_sse_t r ) :
            cbs_base_t( c ), on_session( s ), on_recv( r ) {}

        cbs_cli_sse_t( const cbs_cli_sse_t& cbs ) :
            cbs_base_t( cbs.on_close ), on_session( cbs.on_session ), on_recv( cbs.on_recv ) {}
    };

    /*********************************************************************
     * @brief ...
     */
    struct cbs_cli_wsk_t : public cbs_base_t
    {
        cb_session_wsk_t on_session;
        cb_recv_wsk_t on_recv;

        cbs_cli_wsk_t() {}

        cbs_cli_wsk_t( cb_close_t c, cb_session_wsk_t s, cb_recv_wsk_t r ) :
            cbs_base_t( c ), on_session( s ), on_recv( r ) {}

        cbs_cli_wsk_t( const cbs_cli_wsk_t& cbs ) :
            cbs_base_t( cbs.on_close ), on_session( cbs.on_session ), on_recv( cbs.on_recv ) {}
    };

    /*********************************************************************
     * @brief ...
     */
    struct _session_t :
        public _channel_t
    {
        address_t   addr_;
        hude::any_t user_;
        hude::any_t coder_;

        // buffers_t   buffers_;

        req_t       req_;
        res_t       res_;

        _session_t( const address_t& addr ) : addr_( addr ) {}
    };

    /*********************************************************************
     * @brief ...
     */
    struct _entry_base_t
    {
        virtual ~_entry_base_t() {}

        virtual bool begin ( std::shared_ptr< _session_t > ) = 0;
        virtual void end   ( std::shared_ptr< _session_t > ) = 0;

        virtual state_coder_t encode( std::shared_ptr< _session_t >, hude::any_t ) = 0;
        virtual state_coder_t decode( std::shared_ptr< _session_t > ) = 0;
        virtual std::size_t   timeout( std::shared_ptr< _session_t > ses ) { return 1U; }
    };

    /*********************************************************************
     * @brief ...
     */
    struct _entry_ser_htp_t : public _entry_base_t
    {
        //----------------------------------------------------------------------
        using cbs_t = cbs_ser_htp_t;
        
        //----------------------------------------------------------------------
        cbs_t cbs_;

        //----------------------------------------------------------------------
        _entry_ser_htp_t( const cbs_t& cbs ) : cbs_( cbs ) {}

        //----------------------------------------------------------------------
        bool begin ( std::shared_ptr< _session_t > ses ) override
        {
            this->decode( ses );

            return false;
        }

        //----------------------------------------------------------------------
        void end   ( std::shared_ptr< _session_t > ses ) override
        { if( cbs_.on_close ) cbs_.on_close( ses->user_ ); }

        //----------------------------------------------------------------------
        state_coder_t encode( std::shared_ptr< _session_t >, hude::any_t ) override { return state_coder_t::emERROR; }
        //----------------------------------------------------------------------
        state_coder_t decode( std::shared_ptr< _session_t > ses ) override
        {
            ses->res_.code_ = code_t::emOK;

            if( cbs_.on_reply ) cbs_.on_reply( ses->req_, ses->res_ );

            auto ret = ses->res_.encode( *ses, true );

            if( ret != state_coder_t::emDONE )
            {
                log_err( "http reply error.");
            }

            return ret;
        }
    };

    /*********************************************************************
     * @brief ...
     */
    struct _entry_ser_sse_t : public _entry_base_t
    {
        //----------------------------------------------------------------------
        using cbs_t = cbs_ser_sse_t;
        
        //----------------------------------------------------------------------
        cbs_t           cbs_;
        std::size_t     retry_;

        //----------------------------------------------------------------------
        _entry_ser_sse_t( const cbs_t& cbs, std::size_t retry ) : cbs_( cbs ), retry_( retry ) {}

        //----------------------------------------------------------------------
        bool begin ( std::shared_ptr< _session_t > ses ) override
        {
            ses->res_.res_sse( retry_ );

            if( ses->res_.encode( *ses, false ) == state_coder_t::emDONE )
            {
                ses->coder_ = _coder_sse_t{};

                if( cbs_.on_session ) cbs_.on_session( ses->addr_, ses->user_, std::dynamic_pointer_cast< sender_sse_t >( ses ) );
            } else {
                log_err( "SSE reply error." );
                ses->terminate();
            }

            return true;
        }

        //----------------------------------------------------------------------
        void end   ( std::shared_ptr< _session_t > ses ) override
        { if( cbs_.on_close ) cbs_.on_close( ses->user_ ); }

        //----------------------------------------------------------------------
        state_coder_t encode( std::shared_ptr< _session_t > ses, hude::any_t dat ) override
        {
            auto& coder   = hude::any_cast< _coder_sse_t >( ses->coder_ );
            auto& msg     = hude::any_cast< sse_message_t >( dat );

            auto ret = coder.encode( *ses, msg );

            if( ret == state_coder_t::emERROR )
            {
                log_err( "SSE server encode error." );
                ses->terminate();
            }

            return ret;
        }
        //----------------------------------------------------------------------
        state_coder_t decode( std::shared_ptr< _session_t > ) override { return state_coder_t::emWAITTING; }
    };

    /*********************************************************************
     * @brief ...
     */
    struct _entry_ser_wsk_t : public _entry_base_t
    {
        //----------------------------------------------------------------------
        using cbs_t = cbs_ser_wsk_t;
        
        //----------------------------------------------------------------------
        enum : std::size_t { emTIMEOUT = 3U };

        //----------------------------------------------------------------------
        cbs_t           cbs_;
        std::size_t     timeout_;
        std::size_t     times_;

        //----------------------------------------------------------------------
        _entry_ser_wsk_t( const cbs_t& cbs ) : cbs_( cbs ), timeout_( emTIMEOUT ), times_( 3U ) {}

        //----------------------------------------------------------------------
        bool begin ( std::shared_ptr< _session_t > ses ) override
        {
            if( ! ses->req_.check_wsk() )
            {
                ses->terminate(); return true;
            }

            std::string key;

            if( ! ses->req_.value< std::string >( "Sec-WebSocket-Key", key ) )
            {
                ses->terminate(); return true;
            }

            ses->res_.res_wsk( key );

            if( ses->res_.encode( *ses, false ) == state_coder_t::emDONE )
            {
                ses->coder_ = _coder_wsk_ser_t{};

                if( cbs_.on_session ) cbs_.on_session( ses->addr_, ses->user_, std::dynamic_pointer_cast< sender_wsk_t >( ses ) );
            } else {
                log_err( "Websocket reply error." );
                ses->terminate();
            }

            return true;
        }

        //----------------------------------------------------------------------
        void end   ( std::shared_ptr< _session_t > ses ) override
        { if( cbs_.on_close ) cbs_.on_close( ses->user_ ); }

        //----------------------------------------------------------------------
        state_coder_t encode( std::shared_ptr< _session_t > ses, hude::any_t dat ) override
        {
            auto& coder   = hude::any_cast< _coder_wsk_ser_t >( ses->coder_ );
            auto& msg     = hude::any_cast< sender_wsk_t::message_t >( dat );

            auto ret = coder.encode( *ses, msg );

            if( ret == state_coder_t::emERROR )
            {
                // log_err( "Websoocket server encode error." );
                ses->terminate();
            }

            return ret;
        }

        //----------------------------------------------------------------------
        state_coder_t decode( std::shared_ptr< _session_t > ses ) override
        {
            auto& coder   = hude::any_cast< _coder_wsk_ser_t >( ses->coder_ );

            auto ret = coder.decode( *ses, [=]( const _coder_wsk_ser_t::frame_t& frame, hude::buffer_t& buffer ) {
                if( cbs_.on_recv ) cbs_.on_recv( ses->user_, std::dynamic_pointer_cast< sender_wsk_t >( ses ), frame, buffer );
            } );

            if( ret == state_coder_t::emERROR )
            {
                // log_err( "Websoocket server decode error." );
                ses->terminate();
            }

            return ret;
        }

        //----------------------------------------------------------------------
        std::size_t timeout( std::shared_ptr< _session_t > ses ) override
        {
            timeout_ -= 1;

            if( timeout_ == 0 )
            {
                auto& coder   = hude::any_cast< _coder_wsk_ser_t >( ses->coder_ );

                if( coder.timeout() > ( 3U * 15U ) )
                {
                    return 0U;
                } else {
                    hude::buffer_t out;
                    coder.ping( out );
                    ses->_send( out );
                    timeout_ = emTIMEOUT;
                }
            }

            return timeout_;
        }
    };

    /*********************************************************************
     * @brief ...
     */
    struct _entry_cli_htp_t : public _entry_base_t
    {
        //----------------------------------------------------------------------
        using cbs_t = cbs_cli_htp_t;
        
        //----------------------------------------------------------------------
        cbs_t cbs_;

        //----------------------------------------------------------------------
        _entry_cli_htp_t( const cbs_t& cbs ) : cbs_( cbs ) {}

        //----------------------------------------------------------------------
        bool request( std::shared_ptr< _session_t > ses )
        {
            if( cbs_.on_session ) cbs_.on_session( ses->addr_, ses->req_ );

            if( ses->req_.encode( *ses, true ) == state_coder_t::emDONE )
            {
                return true;
            } else {
                log_err( "HTTP request error." );
                ses->terminate();
                return false;
            }
        }

        //----------------------------------------------------------------------
        bool begin ( std::shared_ptr< _session_t > ses ) override
        {
            if( cbs_.on_reply ) cbs_.on_reply( ses->req_, ses->res_ );

            ses->terminate();

            return true;
        }

        //----------------------------------------------------------------------
        void end   ( std::shared_ptr< _session_t > ses ) override
        { if( cbs_.on_close ) cbs_.on_close( ses->user_ ); }

        //----------------------------------------------------------------------
        state_coder_t encode( std::shared_ptr< _session_t >, hude::any_t ) override { return state_coder_t::emERROR; }
        //----------------------------------------------------------------------
        state_coder_t decode( std::shared_ptr< _session_t > ) override { return state_coder_t::emERROR; }
    };

    /*********************************************************************
     * @brief ...
     */
    struct _entry_cli_sse_t : public _entry_base_t
    {
        //----------------------------------------------------------------------
        using cbs_t = cbs_cli_sse_t;
        
        //----------------------------------------------------------------------
        cbs_t cbs_;

        //----------------------------------------------------------------------
        _entry_cli_sse_t( const cbs_t& cbs ) : cbs_( cbs ) {}

        //----------------------------------------------------------------------
        bool request( std::shared_ptr< _session_t > ses )
        {
            ses->req_.req_sse();

            if( ses->req_.encode( *ses, false ) == state_coder_t::emDONE )
            {
                ses->coder_ = _coder_sse_t{};
                return true;
            } else {
                log_err( "SSE request error." );
                ses->terminate();
                return false;
            }

        }

        //----------------------------------------------------------------------
        bool begin ( std::shared_ptr< _session_t > ses ) override
        {
            if( cbs_.on_session ) cbs_.on_session( ses->addr_, ses->user_ );

            return true;
        }

        //----------------------------------------------------------------------
        void end   ( std::shared_ptr< _session_t > ses ) override
        { if( cbs_.on_close ) cbs_.on_close( ses->user_ ); }

        //----------------------------------------------------------------------
        state_coder_t encode( std::shared_ptr< _session_t >, hude::any_t ) override { return state_coder_t::emERROR; }

        //----------------------------------------------------------------------
        state_coder_t decode( std::shared_ptr< _session_t > ses ) override
        {
            auto& coder   = hude::any_cast< _coder_sse_t >( ses->coder_ );

            auto ret = coder.decode( *ses, [=]( sse_message_t& msg ) {
                if( cbs_.on_recv ) cbs_.on_recv( ses->user_, std::dynamic_pointer_cast< sender_sse_t >( ses ), msg );
            } );

            if( ret == state_coder_t::emERROR )
            {
                log_err( "SSE client decode error." );
                ses->terminate();
            }

            return ret;
        }
    };

    /*********************************************************************
     * @brief ...
     */
    struct _entry_cli_wsk_t : public _entry_base_t
    {
        //----------------------------------------------------------------------
        using cbs_t = cbs_cli_wsk_t;
        
        //----------------------------------------------------------------------
        cbs_t cbs_;

        //----------------------------------------------------------------------
        _entry_cli_wsk_t( const cbs_t& cbs ) : cbs_( cbs ) {}

        //----------------------------------------------------------------------
        bool request( std::shared_ptr< _session_t > ses )
        {
            ses->req_.req_wsk( ses->addr_local(), ses->addr_peer() );

            if( ses->req_.encode( *ses, false ) == state_coder_t::emDONE )
            {
                ses->coder_ = _coder_wsk_cli_t{};
                return true;
            } else {
                log_err( "Websoocket client request error." );
                ses->terminate();
                return false;
            }
        }

        //----------------------------------------------------------------------
        bool begin ( std::shared_ptr< _session_t > ses ) override
        {
            if( cbs_.on_session ) cbs_.on_session( ses->addr_, ses->user_, std::dynamic_pointer_cast< sender_wsk_t >( ses ) );

            return true;
        }

        //----------------------------------------------------------------------
        void end   ( std::shared_ptr< _session_t > ses ) override
        { if( cbs_.on_close ) cbs_.on_close( ses->user_ ); }

        //----------------------------------------------------------------------
        state_coder_t encode( std::shared_ptr< _session_t > ses, hude::any_t dat ) override
        {
            auto& coder   = hude::any_cast< _coder_wsk_cli_t >( ses->coder_ );
            auto& msg     = hude::any_cast< sender_wsk_t::message_t >( dat );

            auto ret = coder.encode( *ses, msg );

            if( ret == state_coder_t::emERROR )
            {
                log_err( "Websoocket client encode error." );
                ses->terminate();
            }

            return ret;
        }

        //----------------------------------------------------------------------
        state_coder_t decode( std::shared_ptr< _session_t > ses ) override
        {
            auto& coder   = hude::any_cast< _coder_wsk_cli_t >( ses->coder_ );

            auto ret = coder.decode( *ses, [=]( const _coder_wsk_cli_t::frame_t& frame, hude::buffer_t& buffer ) {
                if( cbs_.on_recv ) cbs_.on_recv( ses->user_, std::dynamic_pointer_cast< sender_wsk_t >( ses ), frame, buffer );
            } );

            if( ret == state_coder_t::emERROR )
            {
                log_err( "Websoocket client decode error." );
                ses->terminate();
            }

            return ret;
        }
    };

    /*********************************************************************
     * @brief ...
     */
    template< typename _cbs > struct _traits_entry_t;

    template<> struct _traits_entry_t< cbs_ser_htp_t > { using cbs_t = cbs_ser_htp_t;  using entry_t = _entry_ser_htp_t; };
    template<> struct _traits_entry_t< cbs_ser_sse_t > { using cbs_t = cbs_ser_sse_t;  using entry_t = _entry_ser_sse_t; };
    template<> struct _traits_entry_t< cbs_ser_wsk_t > { using cbs_t = cbs_ser_wsk_t;  using entry_t = _entry_ser_wsk_t; };

    template<> struct _traits_entry_t< cbs_cli_htp_t > { using cbs_t = cbs_cli_htp_t;  using entry_t = _entry_cli_htp_t; };
    template<> struct _traits_entry_t< cbs_cli_sse_t > { using cbs_t = cbs_cli_sse_t;  using entry_t = _entry_cli_sse_t; };
    template<> struct _traits_entry_t< cbs_cli_wsk_t > { using cbs_t = cbs_cli_wsk_t;  using entry_t = _entry_cli_wsk_t; };

    /*********************************************************************
     * @brief ...
     */
    using entry_t   = std::shared_ptr< _entry_base_t >;

    /*********************************************************************
     * @brief ...
     */
    class _router_t
    {
    public:
        //----------------------------------------------------------------------
        using entries_t = std::tuple< entry_t, entry_t, entry_t, entry_t >;

        //----------------------------------------------------------------------
        entry_t entry( const std::string& path, method_t method ) const
        {
            std::lock_guard< std::mutex > _al( mutex_ );

            const std::string* ptr = &path;

            for( const auto& i : matchs_ )
            {
                auto pos = path.find( i );

                if( pos == 0 )
                {
                    if( path.size() == i.size() || ( path.size() > i.size() && path[i.size()] == '/' ) )
                        ptr = &i;
                }
            }

            auto itr = map_resource_.find( *ptr );

            if( itr != map_resource_.end() )
            {
                return _entry( itr->second, method );
            }

            return entry_t{};
        }

        //----------------------------------------------------------------------
        bool resource( const std::string& path, method_t method, entry_t entry )
        {
            std::lock_guard< std::mutex > _al( mutex_ );

            auto s = path.size();

            if( path[s-2] == '/' && path[s-1] == '*')
            {
                matchs_.push_back( std::string{ path.begin(), path.end() - 2 } );
                s -= 2;
            }

            auto ret = map_resource_.emplace( std::string{ path.begin(), path.begin() + s }, entries_t{} );

            this->_entry( ret.first->second, method ) = entry;

            return ret.second;
        }

        //----------------------------------------------------------------------
        inline bool method( const std::string& path, cb_reply_t cb, method_t mtd )
        {
            return _method( path, mtd, cb );
        }

        //----------------------------------------------------------------------
        inline bool get( const std::string& path, cb_reply_t cb )
        {
            return _method( path, method_t::emGET, cb );
        }

        //----------------------------------------------------------------------
        inline bool post( const std::string& path, cb_reply_t cb )
        {
            return _method( path, method_t::emPOST, cb );
        }

        //----------------------------------------------------------------------
        inline bool put( const std::string& path, cb_reply_t cb )
        {
            return _method( path, method_t::emPUT, cb );
        }

        //----------------------------------------------------------------------
        inline bool del( const std::string& path, cb_reply_t cb )
        {
            return _method( path, method_t::emDELETE, cb );
        }

        //----------------------------------------------------------------------
        inline bool sse( const std::string& path, cbs_ser_sse_t cbs, std::size_t retry = 3000U )
        {
            return resource( path, method_t::emGET, std::make_shared< _entry_ser_sse_t >( cbs, retry ) );
        }

        //----------------------------------------------------------------------
        inline bool wsk( const std::string& path, cbs_ser_wsk_t cbs )
        {
            return resource( path, method_t::emGET, std::make_shared< _entry_ser_wsk_t >( cbs ) );
        }

    private:
        //----------------------------------------------------------------------
        inline bool _method( const std::string& path, method_t mtd, cb_reply_t cb )
        {
            cbs_ser_htp_t cbs{ cb_close_t{}, cb_session_ser_htp_t{}, cb }; 

            return resource( path, mtd, std::make_shared< _entry_ser_htp_t >( cbs ) );
        }

        //----------------------------------------------------------------------
        entry_t& _entry( entries_t& entries, method_t method )
        {
            static entry_t nul;

            switch ( method )
            {
            case method_t::emGET:    return std::get<0>( entries );
            case method_t::emPOST:   return std::get<1>( entries );
            case method_t::emPUT:    return std::get<2>( entries );
            case method_t::emDELETE: return std::get<3>( entries );
            default: return nul;
            }
        }

        //----------------------------------------------------------------------
        const entry_t& _entry( const entries_t& entries, method_t method ) const
        {
            static const entry_t nul;

            switch ( method )
            {
            case method_t::emGET:    return std::get<0>( entries );
            case method_t::emPOST:   return std::get<1>( entries );
            case method_t::emPUT:    return std::get<2>( entries );
            case method_t::emDELETE: return std::get<3>( entries );
            default: return nul;
            }
        }

    private:
        //----------------------------------------------------------------------
        std::unordered_map< std::string, entries_t >    map_resource_;
        std::list< std::string >                        matchs_;
        mutable std::mutex                              mutex_;

    };

    /*********************************************************************
     * @brief ...
     */
    template< std::size_t _count >
    struct _link_t :
        public ::dnet::_sock_t< _count >,
        public _session_t,
        public sender_sse_t,
        public sender_wsk_t
    {
        //----------------------------------------------------------------------
        using this_t  = _link_t< _count >;
        using base_t  = dnet::_sock_t< _count >;
        using sock_t  = std::shared_ptr< dnet::_sock_t< _count > >;
        using ctx_t   = hude::aio::ctx_t< _count >;
        using event_t = hude::aio::epoll_evt_t;

        //----------------------------------------------------------------------
        std::recursive_mutex                        mutex_;
        std::shared_ptr< _entry_base_t >            entry_;

        //----------------------------------------------------------------------
        _link_t( ctx_t ctx, socket_t sock, const address_t& addr ) :
            base_t( ctx, sock ), _session_t( addr )
        {
        }

        //----------------------------------------------------------------------
        std::shared_ptr< _session_t > session()
        {
            auto ptr = std::dynamic_pointer_cast< this_t >( base_t::ptr() );
            return std::dynamic_pointer_cast< _session_t >( ptr );
        }

        //----------------------------------------------------------------------
        // void _on_send ( sock_t sock ) override {}

        //----------------------------------------------------------------------
        void _on_close( sock_t sock ) override
        {
            base_t::_on_close( sock );

            if( entry_ ) entry_->end( this->session() );
        }

        //----------------------------------------------------------------------
        void terminate() override
        {
            this->close();
        }

        //----------------------------------------------------------------------
        address_t addr_local() override
        {
            address_t addr;
            this->get_addr_local( addr );
            return addr;
        }

        //----------------------------------------------------------------------
        address_t addr_peer() override
        {
            address_t addr;
            this->get_addr_peer( addr );
            return addr;
        }

        //----------------------------------------------------------------------
        int _send( const hude::buffer_t& buffer ) override
        {
            std::unique_lock< std::recursive_mutex > _al( this->mutex_ );

            // log_dug( "link %d send( %u ): %s", **this, buffer.size(), &(buffer[0]) );

            return base_t::send_all( buffer );
        }

        //----------------------------------------------------------------------
        int _recv( hude::buffer_t& buffer, size_t size ) override
        {
            int ret = 0;

            if( size )
            {
                hude::buffer_t buf;
                buf.resize( size );

                auto h = &(buf[0]);
                auto e = h + size;
                auto c = h;

                while( c < e )
                {
                    ret = base_t::recv( c, e - c );

                    if( ret > 0 )
                    {
                        c += ret;
                    } else {
                        buf.resize( c - h );
                        break;
                    }
                }

                ret = (ret > 0)? c - h : ret;
            } else {
                ret = base_t::recv_all( buffer );
                // ret = ( ret == 0 )? 0 : (int)(buffer.size());
            }

            // log_dug( "link %d recv( %u ): %s", **this, buffer.size(), &(buffer[0]) );

            return ret;
        }

        //----------------------------------------------------------------------
        state_coder_t _send_sse( const sse_message_t& msg ) override
        {
            return this->entry_->encode( this->session(), msg );
        }

        //----------------------------------------------------------------------
        state_coder_t _send_wsk( uint8_t cls, const uint8_t* ptr, std::size_t siz ) override
        {
            return this->entry_->encode( this->session(), typename sender_wsk_t::message_t{ cls, ptr, siz } );
        }

        //----------------------------------------------------------------------
        using base_t::send;

        //----------------------------------------------------------------------
        int send( const buffers_t& buffers )
        {
            std::size_t count = 0;

            for( const auto& i : buffers )
            {
                auto ret = base_t::send_all( i );

                if( i.size() == ret )
                    count += i.size();
                else
                    return ret;
            }

            return count;
        }

    };

    /*********************************************************************
     * @brief ...
     */
    template< std::size_t _count >
    struct _link_route_t : public _link_t< _count >
    {
        //----------------------------------------------------------------------
        using this_t  = _link_route_t< _count >;
        using base_t  = _link_t< _count >;
        using sock_t  = std::shared_ptr< dnet::_sock_t< _count > >;
        using ctx_t   = hude::aio::ctx_t< _count >;
        using event_t = hude::aio::epoll_evt_t;

        //----------------------------------------------------------------------
        enum : std::size_t { emTIMEOUT = 3U };

        //----------------------------------------------------------------------
        _router_t*        router_;
        uintptr_t         timer_;
        std::size_t       timeout_;

        //----------------------------------------------------------------------
        _link_route_t( ctx_t ctx, socket_t sock, const address_t& addr, _router_t* r ) :
            base_t( ctx, sock, addr ), router_( r ), timer_( 0U ), timeout_( emTIMEOUT )
        {
            auto on_timer = [=]( uintptr_t, uintptr_t ) -> void
            {
                std::unique_lock< std::recursive_mutex > _al( this->mutex_ );

                if( ! timeout_ )
                {
                    _log_dug( "<aio>", "\t --sock%d(%p)->timeout()", **this, this );

                    if( timer_ )
                    {
                        auto p = base_t::ptr();
                        p->ctx_->task_remove( timer_ );
                        timer_ = 0U;
                        p->close();
                    }
                } else {
                    if( this->entry_ )
                        timeout_ = this->entry_->timeout( this->session() );
                    else
                        timeout_ -= 1;
                }
            };

            auto ret = ctx->task_commit( on_timer, 1000U, 0U );

            timer_ = *ret;
        }

        //----------------------------------------------------------------------
        ~_link_route_t()
        {
            std::unique_lock< std::recursive_mutex > _al( this->mutex_ );

            if( timer_ )
            {
                this->ctx_->task_remove( timer_ );
                timer_ = 0U;
            }
        }

        //----------------------------------------------------------------------
        void _on_recv ( sock_t sock ) override
        {
            auto ses = this->session();

            while( true )
            {
                std::unique_lock< std::recursive_mutex > _al( this->mutex_ );

                if(  this->entry_ )
                {
                    auto ret = this->entry_->decode( ses );

                    switch( ret )
                    {
                    case state_coder_t::emERROR: this->close();
                    case state_coder_t::emWAITTING: return;
                    default: break;
                    };
                } else {
                    // 解析http
                    auto ret = this->req_.decode( *ses );

                    switch ( ret )
                    {
                    case state_coder_t::emDONE: //如果解析完成
                        {
                            auto entry = this->router_->entry( this->req_.path_, this->req_.method_ );

                            if( ! entry )
                            {
                                this->close();
                                return;
                            }

                            this->req_.source_ = this->addr_;

                            if( ! entry->begin( ses ) )
                            {
                                timeout_ = emTIMEOUT;
                            } else {
                                this->entry_ = entry;
                            }
                        }

                        break;
                    
                    case state_coder_t::emERROR: //如果解析数据不正常
                        this->close();
                        return;

                    default:
                        return;
                    }
                }
            }
        }
    };

    /*********************************************************************
     * @brief ...
     */
    template< typename _cbs, std::size_t _count >
    struct _link_connect_t : public _link_t< _count >
    {
        //----------------------------------------------------------------------
        using this_t  = _link_connect_t< _cbs, _count >;
        using base_t  = _link_t< _count >;
        using ctx_t   = hude::aio::ctx_t< _count >;
        using event_t = hude::aio::epoll_evt_t;

        //----------------------------------------------------------------------
        _cbs            cbs_;
        std::string     path_;
        bool            state_;

        //----------------------------------------------------------------------
        _link_connect_t( ctx_t ctx, socket_t sock, const address_t& addr, _cbs cbs, const std::string& path ) :
            base_t( ctx, sock, addr ), cbs_( cbs ), path_( path ), state_( false )
        {
            this->req_.path_ = path;
        }

        //----------------------------------------------------------------------
        // sock可写时发起请求
        void _on_send ( std::shared_ptr< dnet::_sock_t< _count > > sock ) override
        {
            base_t::_on_send( sock );

            typename _traits_entry_t< _cbs >::entry_t entry{ cbs_ };

            entry.request( this->session() );
        }

        //----------------------------------------------------------------------
        // 接收数据，当entry未绑定时由数据发往http握手，绑定后由entry处理
        void _on_recv ( std::shared_ptr< dnet::_sock_t< _count > > sock ) override
        {
            base_t::_on_recv( sock );

            auto ses = this->session();

            while( true )
            {
                std::unique_lock< std::recursive_mutex > _al( this->mutex_ );

                if(  this->entry_ )
                {
                    auto ret = this->entry_->decode( ses );

                    switch( ret )
                    {
                    case state_coder_t::emERROR: this->close();
                    case state_coder_t::emWAITTING: return;
                    default: break;
                    };
                } else {
                    // 解析http
                    auto ret = this->res_.decode( *ses );

                    switch ( ret )
                    {
                    case state_coder_t::emDONE: //如果解析完成
                        this->entry_.reset( new typename _traits_entry_t< _cbs >::entry_t{ cbs_ } );
                        this->entry_->begin( ses );
                        break;
                    
                    case state_coder_t::emERROR: //如果解析数据不正常
                        this->close();
                        return;

                    default:
                        return;
                    }
                }
            }
        }

        //----------------------------------------------------------------------
        bool state() const { return state_; }

        //----------------------------------------------------------------------
        void state( bool s ) { state_ = s;  }
    };

    /*********************************************************************
     * @brief HTTP端口监听
     */
    template< std::size_t _count >
    struct _listen_t :
        public dnet::_service_t< _count >
    {
        //----------------------------------------------------------------------
        enum : std::size_t { emDEFAULT_BACKLOG = ( (_count / 500U) < 2U )? 2U : (_count / 500U) };

        //----------------------------------------------------------------------
        using this_t    = _listen_t< _count >;
        using base_t    = dnet::_service_t< _count >;

        using ctx_t     = typename base_t::ctx_t;

        //----------------------------------------------------------------------
        _router_t* router_;

        //----------------------------------------------------------------------
        _listen_t( ctx_t ctx, const address_t& addr, _router_t* router, std::size_t backlog = emDEFAULT_BACKLOG ) :
            base_t( ctx, dnet::_socket_open( addr.ss_family, SOCK_STREAM, 0 ), addr ), router_( router )
        {
            this->state_ = boot( backlog );
        }

        //----------------------------------------------------------------------
        _listen_t( ctx_t ctx, const char* host, uint16_t port, _router_t* router, std::size_t backlog = emDEFAULT_BACKLOG ) :
            _listen_t( ctx, address_t( host, port, AI_PASSIVE | AI_NUMERICHOST ), router, backlog )
        {
        }

        //----------------------------------------------------------------------
        ~_listen_t()
        {
        }

        //----------------------------------------------------------------------
        // 如果有就绪的连接请求，在线程池内异步创建对应的客户socket对象，触发请求事件，最后加入epoll事件监听
        void _on_recv ( std::shared_ptr< dnet::_sock_t< _count > > sock ) override
        {
            while( true )
            {
                address_t addr;
                socklen_t size = sizeof( address_t );

                auto skt = dnet::_socket_accept( **this, addr.ptr(), &size );
                if( skt < 0 ) return;

                _log_dug( "<aio>", "\t --sock%d(%p)->accept( %d )", **this, this, skt );

                auto ret = sockopts_t::options( skt,
                    sockopts_t::noblock_t{},
                    sockopts_t::linger_t{ 1, 5 },
                    sockopts_t::keepalive_t{ 1, 15, 15, 3 }
                );

                if( ! ret )
                {
                    auto link = dnet::_io_obj< _link_route_t< _count > >( this->ctx_, skt, addr, router_ );

                    link->attach();
                }
            }
        }

        //----------------------------------------------------------------------
        bool boot( std::size_t backlog )
        {
            {
                auto ret = sockopts_t::options( **this, sockopts_t::reuse_addr_t{ 1 } );
                if( ret ) return false;
            }

            if( this->empty() || ! this->ctx_ ) return false;

            {
                auto ret = dnet::_socket_bind( **this, this->addr_.ptr(), this->addr_.len() );
                if( ret ) return false;
            }

            {
                auto ret = dnet::_socket_listen( **this, backlog );
                if( ret ) return false;
            }

            {
                auto ret = sockopts_t::options( **this,
                    sockopts_t::noblock_t{},
                    sockopts_t::linger_t{ 1, 5 },
                    sockopts_t::keepalive_t{ 1, 15, 15, 3 }
                );

                if( ret ) return false;
            }

            return true;
        }
    };

    /*********************************************************************
     * @brief TCP连接
     */
    template< typename _cbs, std::size_t _count >
    struct _connect_t :
        public  _link_connect_t< _cbs, _count >
    {
        //----------------------------------------------------------------------
        using this_t    = _connect_t< _cbs, _count >;
        using base_t    = _link_connect_t< _cbs, _count >;
        using ctx_t     = typename base_t::ctx_t;

        //----------------------------------------------------------------------
        _connect_t( ctx_t ctx, const address_t& addr, const _cbs& cbs, const std::string& path ) :
            base_t( ctx, dnet::_socket_open( addr.ss_family, SOCK_STREAM, 0 ), addr, cbs, path )
        {
            this->state_ = boot();
        }

        //----------------------------------------------------------------------
        _connect_t( ctx_t ctx, const char* host, uint16_t port, const _cbs& cbs, const std::string& path ) :
            _connect_t( ctx, address_t( host, port ), cbs, path )
        {
        }

        //----------------------------------------------------------------------
        ~_connect_t()
        {
        }

        //----------------------------------------------------------------------
        bool boot()
        {
            {
                auto ret = sockopts_t::options( **this, sockopts_t::reuse_addr_t{ 1 } );
                if( ret ) return false;
            }

            {
                auto ret = dnet::_socket_connect( **this, this->addr_.ptr(), this->addr_.len() );
                if( ret && errno != ERR_SOCK_WAITTING ) return false;
            }

            {
                auto ret = sockopts_t::options( **this,
                    sockopts_t::noblock_t{},
                    sockopts_t::linger_t{ 1, 5 },
                    sockopts_t::keepalive_t{ 1, 15, 15, 3 }
                );

                if( ret ) return false;
            }

            return true;
        }
    };

    /*********************************************************************
     * @brief HTTP端口监听包装器
     */
    template< std::size_t _count >
    class http_listen_t : public _router_t
    {
    public:
        //----------------------------------------------------------------------
        enum : std::size_t { emDEFAULT_BACKLOG = ( (_count / 500U) < 2U )? 2U : (_count / 500U) };

        //----------------------------------------------------------------------
        using ctx_t     = typename hude::aio::ctx_t< _count >;

        //----------------------------------------------------------------------
        http_listen_t() {}

        //----------------------------------------------------------------------
        http_listen_t( const http_listen_t& ins ) : listen_( ins.listen_ ) {}

        //----------------------------------------------------------------------
        http_listen_t& operator=( const http_listen_t& ins ) { listen_ = ins.listen_; return *this; }

        //----------------------------------------------------------------------
        http_listen_t( ctx_t ctx, const address_t& addr, std::size_t backlog = emDEFAULT_BACKLOG )
        {
            _listen( ctx, addr, backlog );
        }

        //----------------------------------------------------------------------
        http_listen_t( ctx_t ctx, const char* host, uint16_t port, std::size_t backlog = emDEFAULT_BACKLOG )
        {
            _listen( ctx, address_t{ host, port }, backlog );
        }

        //----------------------------------------------------------------------
        bool listen( ctx_t ctx, const address_t& addr, std::size_t backlog = emDEFAULT_BACKLOG )
        {
            return _listen( ctx, addr, backlog );
        }

        //----------------------------------------------------------------------
        bool listen( ctx_t ctx, const char* host, uint16_t port, std::size_t backlog = emDEFAULT_BACKLOG )
        {
            return _listen( ctx, address_t{ host, port }, backlog );
        }

        //----------------------------------------------------------------------
        bool operator()( ctx_t ctx, const address_t& addr, std::size_t backlog = emDEFAULT_BACKLOG )
        {
            return _listen( ctx, addr, backlog );
        }

        //----------------------------------------------------------------------
        bool operator()( ctx_t ctx, const char* host, uint16_t port, std::size_t backlog = emDEFAULT_BACKLOG )
        {
            return _listen( ctx, address_t{ host, port }, backlog );
        }

        //----------------------------------------------------------------------
        hude::optional_t< bool > state() const { return ( listen_ )? listen_->state() : hude::optional_t< bool >{}; }

        //----------------------------------------------------------------------
        const char* error() const { return listen_? listen_->error() : nullptr; }

    private:
        //----------------------------------------------------------------------
        bool _listen( ctx_t ctx, const address_t& addr, std::size_t backlog )
        {
            listen_ = dnet::io_obj< _listen_t< _count > >( ctx, addr, this, backlog );

            return listen_->state();
        }

    private:
        std::shared_ptr< _listen_t< _count > > listen_;

    };

    /*********************************************************************
     * @brief TCP连接包装器
     */
    template< typename _cbs, std::size_t _count >
    class http_connect_t : public _router_t
    {
    public:
        //----------------------------------------------------------------------
        using ctx_t     = typename hude::aio::ctx_t< _count >;

        //----------------------------------------------------------------------
        http_connect_t() {}

        //----------------------------------------------------------------------
        http_connect_t( const http_connect_t& ins ) : connect_( ins.connect_ ) {}

        //----------------------------------------------------------------------
        http_connect_t& operator=( const http_connect_t& ins ) { connect_ = ins.connect_; return *this; }

        //----------------------------------------------------------------------
        http_connect_t( ctx_t ctx, const address_t& addr, const _cbs& cbs, const std::string& path )
        {
            _connect( ctx, addr, cbs, path );
        }

        //----------------------------------------------------------------------
        http_connect_t( ctx_t ctx, const char* host, uint16_t port, const _cbs& cbs, const std::string& path )
        {
            _connect( ctx, address_t{ host, port }, cbs, path );
        }

        //----------------------------------------------------------------------
        bool connect( ctx_t ctx, const address_t& addr, const _cbs& cbs, const std::string& path )
        {
            return _connect( ctx, addr, cbs, path );
        }

        //----------------------------------------------------------------------
        bool connect( ctx_t ctx, const char* host, uint16_t port, const _cbs& cbs, const std::string& path )
        {
            return _connect( ctx, address_t{ host, port }, cbs, path );
        }

        //----------------------------------------------------------------------
        bool operator()( ctx_t ctx, const address_t& addr, const _cbs& cbs, const std::string& path )
        {
            return _connect( ctx, addr, cbs, path );
        }

        //----------------------------------------------------------------------
        bool operator()( ctx_t ctx, const char* host, uint16_t port, const _cbs& cbs, const std::string& path )
        {
            return _connect( ctx, address_t{ host, port }, cbs, path );
        }

        //----------------------------------------------------------------------
        hude::optional_t< bool > state() const { return ( connect_ )? connect_->state() : hude::optional_t< bool >{}; }

        //----------------------------------------------------------------------
        const char* error() const { return connect_? connect_->error() : nullptr; }

    private:
        //----------------------------------------------------------------------
        bool _connect( ctx_t ctx, const address_t& addr, const _cbs& cbs, const std::string& path )
        {
            return ( connect_ = dnet::io_obj< _connect_t< _cbs, _count > >( ctx, addr, cbs, path ) )->state();
        }

    private:
        std::shared_ptr< _connect_t< _cbs, _count > > connect_;

    };

#if defined( _WIN32 ) || defined( _WIN64 )
#   define _PATH_SPR '\\'
#else
#   define _PATH_SPR '/'
#endif

    /*********************************************************************
     * @brief static_resource_t
     */
    struct static_resource_t
    {
        std::string perfix, path, content;

        static_resource_t( const std::string& resource, const std::string& local, const char* type = nullptr ) :
            perfix( resource ), path( local ), content( type? type : std::string{} ) {}

        void operator()( const req_t& req, res_t& res )
        {
            std::string name, file;

            {
                auto s = req.path_.find( perfix );
                if( s != 0 )
                {
                    res( code_t::emREQ_INVALID );
                    return;
                }

                name = req.path_.substr( perfix.size() );

                file = path;
                if( path[path.size() - 1] != _PATH_SPR ) file += _PATH_SPR;
                file += name;
            }

            auto fp = fopen( file.c_str(), "rb" );
            if( ! fp )
            {
                log_err( "error: open file %s", file.c_str() );
                res( code_t::emINTER_ERROR );
                return;
            }

            fseek( fp, 0, SEEK_END );

            auto siz = ftell( fp );

            res.payload_.resize( siz );

            rewind( fp );

            int r = fread( &(res.payload_[0]), sizeof(char), siz, fp );

            fclose( fp );

            if( siz == r )
            {
                if( content.empty() )
                {
                    auto pos = name.find_last_of( '.' );
                    if( pos == std::string::npos )
                        res.head( "Content-Type", get_content_type( nullptr ) );
                    else
                        res.head( "Content-Type", get_content_type( name.substr( pos ).c_str() ) );
                } else {
                    res.head( "Content-Type", content.c_str() );
                }
            } else {
                log_err( "error: read file %s( %d : %d )", file.c_str(), siz, r );
                res.payload_.clear();
                res( code_t::emINTER_ERROR );
            }
        }

        static const char* get_content_type( const char* type )
        {
            static const std::map< std::string, const char* > cts =
            {
                { ".001",	 "application/x-001"	}, { ".301",	"application/x-301"	},
                { ".323",	 "text/h323"	}, { ".906",	"application/x-906"	},
                { ".907",	 "drawing/907"	}, { ".a11",	"application/x-a11"	},
                { ".acp",	 "audio/x-mei-aac"	}, { ".ai",	"application/postscript"	},
                { ".aif",	 "audio/aiff"	}, { ".aifc",	"audio/aiff"	},
                { ".aiff",	 "audio/aiff"	}, { ".anv",	"application/x-anv"	},
                { ".asa",	 "text/asa"	}, { ".asf",	"video/x-ms-asf"	},
                { ".asp",	 "text/asp"	}, { ".asx",	"video/x-ms-asf"	},
                { ".au",	 "audio/basic"	}, { ".avi",	"video/avi"	},
                { ".awf",	 "application/vnd.adobe.workflow"	}, { ".biz",	"text/xml"	},
                { ".bmp",	 "application/x-bmp"	}, { ".bot",	"application/x-bot"	},
                { ".c4t",	 "application/x-c4t"	}, { ".c90",	"application/x-c90"	},
                { ".cal",	 "application/x-cals"	}, { ".cat",	"application/vnd.ms-pki.seccat"	},
                { ".cdf",	 "application/x-netcdf"	}, { ".cdr",	"application/x-cdr"	},
                { ".cel",	 "application/x-cel"	}, { ".cer",	"application/x-x509-ca-cert"	},
                { ".cg4",	 "application/x-g4"	}, { ".cgm",	"application/x-cgm"	},
                { ".cit",	 "application/x-cit"	}, { ".class",	"java/*"	},
                { ".cml",	 "text/xml"	}, { ".cmp",	"application/x-cmp"	},
                { ".cmx",	 "application/x-cmx"	}, { ".cot",	"application/x-cot"	},
                { ".crl",	 "application/pkix-crl"	}, { ".crt",	"application/x-x509-ca-cert"	},
                { ".csi",	 "application/x-csi"	}, { ".css",	"text/css"	},
                { ".cut",	 "application/x-cut"	}, { ".dbf",	"application/x-dbf"	},
                { ".dbm",	 "application/x-dbm"	}, { ".dbx",	"application/x-dbx"	},
                { ".dcd",	 "text/xml"	}, { ".dcx",	"application/x-dcx"	},
                { ".der",	 "application/x-x509-ca-cert"	}, { ".dgn",	"application/x-dgn"	},
                { ".dib",	 "application/x-dib"	}, { ".dll",	"application/x-msdownload"	},
                { ".doc",	 "application/msword"	}, { ".dot",	"application/msword"	},
                { ".drw",	 "application/x-drw"	}, { ".dtd",	"text/xml"	},
                { ".dwf",	 "Model/vnd.dwf"	}, { ".dwf",	"application/x-dwf"	},
                { ".dwg",	 "application/x-dwg"	}, { ".dxb",	"application/x-dxb"	},
                { ".dxf",	 "application/x-dxf"	}, { ".edn",	"application/vnd.adobe.edn"	},
                { ".emf",	 "application/x-emf"	}, { ".eml",	"message/rfc822"	},
                { ".ent",	 "text/xml"	}, { ".epi",	"application/x-epi"	},
                { ".eps",	 "application/x-ps"	}, { ".eps",	"application/postscript"	},
                { ".etd",	 "application/x-ebx"	}, { ".exe",	"application/x-msdownload"	},
                { ".fax",	 "image/fax"	}, { ".fdf",	"application/vnd.fdf"	},
                { ".fif",	 "application/fractals"	}, { ".fo",	"text/xml"	},
                { ".frm",	 "application/x-frm"	}, { ".g4",	"application/x-g4"	},
                { ".gbr",	 "application/x-gbr"	}, { ".",	"application/x-"	},
                { ".gif",	 "image/gif"	}, { ".gl2",	"application/x-gl2"	},
                { ".gp4",	 "application/x-gp4"	}, { ".hgl",	"application/x-hgl"	},
                { ".hmr",	 "application/x-hmr"	}, { ".hpg",	"application/x-hpgl"	},
                { ".hpl",	 "application/x-hpl"	}, { ".hqx",	"application/mac-binhex40"	},
                { ".hrf",	 "application/x-hrf"	}, { ".hta",	"application/hta"	},
                { ".htc",	 "text/x-component"	}, { ".htm",	"text/html"	},
                { ".html",	 "text/html"	}, { ".htt",	"text/webviewhtml"	},
                { ".htx",	 "text/html"	}, { ".icb",	"application/x-icb"	},
                { ".ico",	 "image/x-icon"	}, { ".ico",	"application/x-ico"	},
                { ".iff",	 "application/x-iff"	}, { ".ig4",	"application/x-g4"	},
                { ".igs",	 "application/x-igs"	}, { ".iii",	"application/x-iphone"	},
                { ".img",	 "application/x-img"	}, { ".ins",	"application/x-internet-signup"	},
                { ".isp",	 "application/x-internet-signup"	}, { ".IVF",	"video/x-ivf"	},
                { ".java",	 "java/*"	}, { ".jfif",	"image/jpeg"	},
                { ".jpe",	 "image/jpeg"	}, { ".jpe",	"application/x-jpe"	},
                { ".jpeg",	 "image/jpeg"	}, { ".jpg",	"image/jpeg"	},
                { ".jpg",	 "application/x-jpg"	}, { ".js",	"application/x-javascript"	},
                { ".jsp",	 "text/html"	}, { ".la1",	"audio/x-liquid-file"	},
                { ".lar",	 "application/x-laplayer-reg"	}, { ".latex",	"application/x-latex"	},
                { ".lavs",	 "audio/x-liquid-secure"	}, { ".lbm",	"application/x-lbm"	},
                { ".lmsff",	 "audio/x-la-lms"	}, { ".ls",	"application/x-javascript"	},
                { ".ltr",	 "application/x-ltr"	}, { ".m1v",	"video/x-mpeg"	},
                { ".m2v",	 "video/x-mpeg"	}, { ".m3u",	"audio/mpegurl"	},
                { ".m4e",	 "video/mpeg4"	}, { ".mac",	"application/x-mac"	},
                { ".man",	 "application/x-troff-man"	}, { ".math",	"text/xml"	},
                { ".mdb",	 "application/msaccess"	}, { ".mdb",	"application/x-mdb"	},
                { ".mfp",	 "application/x-shockwave-flash"	}, { ".mht",	"message/rfc822"	},
                { ".mhtml",	 "message/rfc822"	}, { ".mi",	"application/x-mi"	},
                { ".mid",	 "audio/mid"	}, { ".midi",	"audio/mid"	},
                { ".mil",	 "application/x-mil"	}, { ".mml",	"text/xml"	},
                { ".mnd",	 "audio/x-musicnet-download"	}, { ".mns",	"audio/x-musicnet-stream"	},
                { ".mocha",	 "application/x-javascript"	}, { ".movie",	"video/x-sgi-movie"	},
                { ".mp1",	 "audio/mp1"	}, { ".mp2",	"audio/mp2"	},
                { ".mp2v",	 "video/mpeg"	}, { ".mp3",	"audio/mp3"	},
                { ".mp4",	 "video/mpeg4"	}, { ".mpa",	"video/x-mpg"	},
                { ".mpd",	 "application/vnd.ms-project"	}, { ".mpe",	"video/x-mpeg"	},
                { ".mpeg",	 "video/mpg"	}, { ".mpg",	"video/mpg"	},
                { ".mpga",	 "audio/rn-mpeg"	}, { ".mpp",	"application/vnd.ms-project"	},
                { ".mps",	 "video/x-mpeg"	}, { ".mpt",	"application/vnd.ms-project"	},
                { ".mpv",	 "video/mpg"	}, { ".mpv2",	"video/mpeg"	},
                { ".mpw",	 "application/vnd.ms-project"	}, { ".mpx",	"application/vnd.ms-project"	},
                { ".mtx",	 "text/xml"	}, { ".mxp",	"application/x-mmxp"	},
                { ".net",	 "image/pnetvue"	}, { ".nrf",	"application/x-nrf"	},
                { ".nws",	 "message/rfc822"	}, { ".odc",	"text/x-ms-odc"	},
                { ".out",	 "application/x-out"	}, { ".p10",	"application/pkcs10"	},
                { ".p12",	 "application/x-pkcs12"	}, { ".p7b",	"application/x-pkcs7-certificates"	},
                { ".p7c",	 "application/pkcs7-mime"	}, { ".p7m",	"application/pkcs7-mime"	},
                { ".p7r",	 "application/x-pkcs7-certreqresp"	}, { ".p7s",	"application/pkcs7-signature"	},
                { ".pc5",	 "application/x-pc5"	}, { ".pci",	"application/x-pci"	},
                { ".pcl",	 "application/x-pcl"	}, { ".pcx",	"application/x-pcx"	},
                { ".pdf",	 "application/pdf"	}, { ".pdf",	"application/pdf"	},
                { ".pdx",	 "application/vnd.adobe.pdx"	}, { ".pfx",	"application/x-pkcs12"	},
                { ".pgl",	 "application/x-pgl"	}, { ".pic",	"application/x-pic"	},
                { ".pko",	 "application/vnd.ms-pki.pko"	}, { ".pl",	"application/x-perl"	},
                { ".plg",	 "text/html"	}, { ".pls",	"audio/scpls"	},
                { ".plt",	 "application/x-plt"	}, { ".png",	"image/png"	},
                { ".png",	 "application/x-png"	}, { ".pot",	"application/vnd.ms-powerpoint"	},
                { ".ppa",	 "application/vnd.ms-powerpoint"	}, { ".ppm",	"application/x-ppm"	},
                { ".pps",	 "application/vnd.ms-powerpoint"	}, { ".ppt",	"application/vnd.ms-powerpoint"	},
                { ".ppt",	 "application/x-ppt"	}, { ".pr",	"application/x-pr"	},
                { ".prf",	 "application/pics-rules"	}, { ".prn",	"application/x-prn"	},
                { ".prt",	 "application/x-prt"	}, { ".ps",	"application/x-ps"	},
                { ".ps",	 "application/postscript"	}, { ".ptn",	"application/x-ptn"	},
                { ".pwz",	 "application/vnd.ms-powerpoint"	}, { ".r3t",	"text/vnd.rn-realtext3d"	},
                { ".ra",	 "audio/vnd.rn-realaudio"	}, { ".ram",	"audio/x-pn-realaudio"	},
                { ".ras",	 "application/x-ras"	}, { ".rat",	"application/rat-file"	},
                { ".rdf",	 "text/xml"	}, { ".rec",	"application/vnd.rn-recording"	},
                { ".red",	 "application/x-red"	}, { ".rgb",	"application/x-rgb"	},
                { ".rjs",	 "application/vnd.rn-realsystem-rjs"	}, { ".rjt",	"application/vnd.rn-realsystem-rjt"	},
                { ".rlc",	 "application/x-rlc"	}, { ".rle",	"application/x-rle"	},
                { ".rm",	 "application/vnd.rn-realmedia"	}, { ".rmf",	"application/vnd.adobe.rmf"	},
                { ".rmi",	 "audio/mid"	}, { ".rmj",	"application/vnd.rn-realsystem-rmj"	},
                { ".rmm",	 "audio/x-pn-realaudio"	}, { ".rmp",	"application/vnd.rn-rn_music_package"	},
                { ".rms",	 "application/vnd.rn-realmedia-secure"	}, { ".rmvb",	"application/vnd.rn-realmedia-vbr"	},
                { ".rmx",	 "application/vnd.rn-realsystem-rmx"	}, { ".rnx",	"application/vnd.rn-realplayer"	},
                { ".rp",	 "image/vnd.rn-realpix"	}, { ".rpm",	"audio/x-pn-realaudio-plugin"	},
                { ".rsml",	 "application/vnd.rn-rsml"	}, { ".rt",	"text/vnd.rn-realtext"	},
                { ".rtf",	 "application/msword"	}, { ".rtf",	"application/x-rtf"	},
                { ".rv",	 "video/vnd.rn-realvideo"	}, { ".sam",	"application/x-sam"	},
                { ".sat",	 "application/x-sat"	}, { ".sdp",	"application/sdp"	},
                { ".sdw",	 "application/x-sdw"	}, { ".sit",	"application/x-stuffit"	},
                { ".slb",	 "application/x-slb"	}, { ".sld",	"application/x-sld"	},
                { ".slk",	 "drawing/x-slk"	}, { ".smi",	"application/smil"	},
                { ".smil",	 "application/smil"	}, { ".smk",	"application/x-smk"	},
                { ".snd",	 "audio/basic"	}, { ".sol",	"text/plain"	},
                { ".sor",	 "text/plain"	}, { ".spc",	"application/x-pkcs7-certificates"	},
                { ".spl",	 "application/futuresplash"	}, { ".spp",	"text/xml"	},
                { ".ssm",	 "application/streamingmedia"	}, { ".sst",	"application/vnd.ms-pki.certstore"	},
                { ".stl",	 "application/vnd.ms-pki.stl"	}, { ".stm",	"text/html"	},
                { ".sty",	 "application/x-sty"	}, { ".svg",	"text/xml"	},
                { ".swf",	 "application/x-shockwave-flash"	}, { ".tdf",	"application/x-tdf"	},
                { ".tg4",	 "application/x-tg4"	}, { ".tga",	"application/x-tga"	},
                { ".tif",	 "image/tiff"	}, { ".tif",	"application/x-tif"	},
                { ".tiff",	 "image/tiff"	}, { ".tld",	"text/xml"	},
                { ".top",	 "drawing/x-top"	}, { ".torrent",	"application/x-bittorrent"	},
                { ".tsd",	 "text/xml"	}, { ".txt",	"text/plain"	},
                { ".uin",	 "application/x-icq"	}, { ".uls",	"text/iuls"	},
                { ".vcf",	 "text/x-vcard"	}, { ".vda",	"application/x-vda"	},
                { ".vdx",	 "application/vnd.visio"	}, { ".vml",	"text/xml"	},
                { ".vpg",	 "application/x-vpeg005"	}, { ".vsd",	"application/vnd.visio"	},
                { ".vsd",	 "application/x-vsd"	}, { ".vss",	"application/vnd.visio"	},
                { ".vst",	 "application/vnd.visio"	}, { ".vst",	"application/x-vst"	},
                { ".vsw",	 "application/vnd.visio"	}, { ".vsx",	"application/vnd.visio"	},
                { ".vtx",	 "application/vnd.visio"	}, { ".vxml",	"text/xml"	},
                { ".wav",	 "audio/wav"	}, { ".wax",	"audio/x-ms-wax"	},
                { ".wb1",	 "application/x-wb1"	}, { ".wb2",	"application/x-wb2"	},
                { ".wb3",	 "application/x-wb3"	}, { ".wbmp",	"image/vnd.wap.wbmp"	},
                { ".wiz",	 "application/msword"	}, { ".wk3",	"application/x-wk3"	},
                { ".wk4",	 "application/x-wk4"	}, { ".wkq",	"application/x-wkq"	},
                { ".wks",	 "application/x-wks"	}, { ".wm",	"video/x-ms-wm"	},
                { ".wma",	 "audio/x-ms-wma"	}, { ".wmd",	"application/x-ms-wmd"	},
                { ".wmf",	 "application/x-wmf"	}, { ".wml",	"text/vnd.wap.wml"	},
                { ".wmv",	 "video/x-ms-wmv"	}, { ".wmx",	"video/x-ms-wmx"	},
                { ".wmz",	 "application/x-ms-wmz"	}, { ".wp6",	"application/x-wp6"	},
                { ".wpd",	 "application/x-wpd"	}, { ".wpg",	"application/x-wpg"	},
                { ".wpl",	 "application/vnd.ms-wpl"	}, { ".wq1",	"application/x-wq1"	},
                { ".wr1",	 "application/x-wr1"	}, { ".wri",	"application/x-wri"	},
                { ".wrk",	 "application/x-wrk"	}, { ".ws",	"application/x-ws"	},
                { ".ws2",	 "application/x-ws"	}, { ".wsc",	"text/scriptlet"	},
                { ".wsdl",	 "text/xml"	}, { ".wvx",	"video/x-ms-wvx"	},
                { ".xdp",	 "application/vnd.adobe.xdp"	}, { ".xdr",	"text/xml"	},
                { ".xfd",	 "application/vnd.adobe.xfd"	}, { ".xfdf",	"application/vnd.adobe.xfdf"	},
                { ".xhtml",	 "text/html"	}, { ".xls",	"application/vnd.ms-excel"	},
                { ".xls",	 "application/x-xls"	}, { ".xlw",	"application/x-xlw"	},
                { ".xml",	 "text/xml"	}, { ".xpl",	"audio/scpls"	},
                { ".xq",	 "text/xml"	}, { ".xql",	"text/xml"	},
                { ".xquery",	 "text/xml"	}, { ".xsd",	"text/xml"	},
                { ".xsl",	 "text/xml"	}, { ".xslt",	"text/xml"	},
                { ".xwd",	 "application/x-xwd"	}, { ".x_b",	"application/x-x_b"	},
                { ".sis",	 "application/vnd.symbian.install"	}, { ".sisx",	"application/vnd.symbian.install"	},
                { ".x_t",	 "application/x-x_t"	}, { ".ipa",	"application/vnd.iphone"	},
                { ".apk",	 "application/vnd.android.package-archive"	}, { ".xap",	"application/x-silverlight-app"	},
                { ".tif",	 "image/tiff" }
            };

            const auto itr = ( type )? cts.find( type ) : cts.cend();

            return ( itr == cts.cend() )? "application/octet-stream" : itr->second;
        }
    };
} //namespace http_v11

//----------------------------------------------------------------------------------------------
namespace hude
{
    namespace http
    {
        template< std::size_t _count = hude::aio::emDEFAULT_MAX_EPOLL >
        struct http_t
        {
            //----------------------------------------------------------------------
            enum : std::size_t { emCOUNT = _count };

            //----------------------------------------------------------------------
            using aio_t                     = hude::aio::ctx_t< _count >;

            //----------------------------------------------------------------------
            using user_t                    = hude::any_t;

            //----------------------------------------------------------------------
            using method_t                  = http_v11::method_t;
            using code_t                    = http_v11::code_t;
            using state_t                   = http_v11::state_coder_t;

            //----------------------------------------------------------------------
            using req_t                     = http_v11::req_t;
            using res_t                     = http_v11::res_t;

            //----------------------------------------------------------------------
            using sse_t                     = http_v11::sse_message_t;
            using head_t                    = typename http_v11::_coder_wsk_t::frame_t;

            //----------------------------------------------------------------------
            using address_t                 = dnet::address_t;
            using buffer_t                  = hude::buffer_t;

            //----------------------------------------------------------------------
            using raw_sender_sse_t          = http_v11::sender_sse_t;
            using raw_sender_wsk_t          = http_v11::sender_wsk_t;

            using sender_sse_t              = std::shared_ptr< http_v11::sender_sse_t >;
            using sender_wsk_t              = std::shared_ptr< http_v11::sender_wsk_t >;

            //----------------------------------------------------------------------
            using on_session_cli_htp_t      = http_v11::cb_session_cli_htp_t;
            using on_session_cli_sse_t      = http_v11::cb_session_cli_sse_t;
            using on_session_ser_htp_t      = http_v11::cb_session_ser_htp_t;
            using on_session_ser_sse_t      = http_v11::cb_session_ser_sse_t;
            using on_session_wsk_t          = http_v11::cb_session_wsk_t;

            using on_recv_sse_t             = http_v11::cb_recv_sse_t;
            using on_recv_wsk_t             = http_v11::cb_recv_wsk_t;
            using on_reply_t                = http_v11::cb_reply_t;

            using on_close_t                = http_v11::cb_close_t;

            //----------------------------------------------------------------------
            using evts_cli_htp_t            = http_v11::cbs_cli_htp_t;
            using evts_cli_sse_t            = http_v11::cbs_cli_sse_t;
            using evts_cli_wsk_t            = http_v11::cbs_cli_wsk_t;

            using evts_ser_htp_t            = http_v11::cbs_ser_htp_t;
            using evts_ser_sse_t            = http_v11::cbs_ser_sse_t;
            using evts_ser_wsk_t            = http_v11::cbs_ser_wsk_t;

            //----------------------------------------------------------------------
            using router_t                  = http_v11::_router_t;

            //----------------------------------------------------------------------
            using http_listen_t             = http_v11::http_listen_t< _count >;

            //----------------------------------------------------------------------
            template< typename _cbs >
            using http_connect_t            = http_v11::http_connect_t< _cbs, _count >;

            //----------------------------------------------------------------------
            template< typename _evts >
            using traits_t                  = http_v11::_traits_entry_t< _evts >;

            //----------------------------------------------------------------------
            using static_resource_t         = http_v11::static_resource_t;

            //----------------------------------------------------------------------
            template< typename _value >
            static inline _value& user_cast( const user_t& user ) { return hude::any_cast< _value >( user ); }

            //----------------------------------------------------------------------
            static inline aio_t aio() { return hude::aio::context_t< _count >::ctx(); }
        };

    } // namespace http
} //namespace hude

#endif //__http_kenny_ojii2fwoeeif9w23__